From 054f8673222625c2866042b89c7bb5803f7e28d3 Mon Sep 17 00:00:00 2001
From: Robert Brignull <robertbrignull@gmail.com>
Date: Tue, 26 May 2020 19:23:28 +0100
Subject: [PATCH] make config file parsing more strict

---
 lib/config-utils.js          | 104 ++++++++++++++------
 lib/config-utils.js.map      |   2 +-
 lib/config-utils.test.js     | 131 ++++++-------------------
 lib/config-utils.test.js.map |   2 +-
 src/config-utils.test.ts     | 185 +++++++++++++----------------------
 src/config-utils.ts          | 105 ++++++++++++++------
 6 files changed, 252 insertions(+), 277 deletions(-)

diff --git a/lib/config-utils.js b/lib/config-utils.js
index 13882c5a0..f0fd07731 100644
--- a/lib/config-utils.js
+++ b/lib/config-utils.js
@@ -13,6 +13,12 @@ const fs = __importStar(require("fs"));
 const yaml = __importStar(require("js-yaml"));
 const path = __importStar(require("path"));
 const util = __importStar(require("./util"));
+const NAME_PROPERTY = 'name';
+const DISPLAY_DEFAULT_QUERIES_PROPERTY = 'disable-default-queries';
+const QUERIES_PROPERTY = 'queries';
+const QUERIES_USES_PROPERTY = 'uses';
+const PATHS_IGNORE_PROPERTY = 'paths-ignore';
+const PATHS_PROPERTY = 'paths';
 class ExternalQuery {
     constructor(repository, ref) {
         this.path = '';
@@ -30,12 +36,12 @@ class Config {
         this.pathsIgnore = [];
         this.paths = [];
     }
-    addQuery(queryUses) {
+    addQuery(configFile, queryUses) {
         // The logic for parsing the string is based on what actions does for
         // parsing the 'uses' actions in the workflow file
         queryUses = queryUses.trim();
         if (queryUses === "") {
-            throw new Error(getQueryUsesBlank());
+            throw new Error(getQueryUsesInvalid(configFile));
         }
         // Check for the local path case before we start trying to parse the repository name
         if (queryUses.startsWith("./")) {
@@ -44,7 +50,7 @@ class Config {
         }
         let tok = queryUses.split('@');
         if (tok.length !== 2) {
-            throw new Error(getQueryUsesIncorrect(queryUses));
+            throw new Error(getQueryUsesInvalid(configFile, queryUses));
         }
         const ref = tok[1];
         tok = tok[0].split('/');
@@ -52,14 +58,14 @@ class Config {
         // The second token is the repo
         // The rest is a path, if there is more than one token combine them to form the full path
         if (tok.length < 2) {
-            throw new Error(getQueryUsesIncorrect(queryUses));
+            throw new Error(getQueryUsesInvalid(configFile, queryUses));
         }
         if (tok.length > 3) {
             tok = [tok[0], tok[1], tok.slice(2).join('/')];
         }
         // Check none of the parts of the repository name are empty
         if (tok[0].trim() === '' || tok[1].trim() === '') {
-            throw new Error(getQueryUsesIncorrect(queryUses));
+            throw new Error(getQueryUsesInvalid(configFile, queryUses));
         }
         let external = new ExternalQuery(tok[0] + '/' + tok[1], ref);
         if (tok.length === 3) {
@@ -69,14 +75,31 @@ class Config {
     }
 }
 exports.Config = Config;
-function getQueryUsesBlank() {
-    return '"uses" value for queries cannot be blank';
+function getNameInvalid(configFile) {
+    return getConfigFilePropertyError(configFile, NAME_PROPERTY, 'must be a non-empty string');
 }
-exports.getQueryUsesBlank = getQueryUsesBlank;
-function getQueryUsesIncorrect(queryUses) {
-    return '"uses" value for queries must be a path, or owner/repo@ref \n Found: ' + queryUses;
+exports.getNameInvalid = getNameInvalid;
+function getDisableDefaultQueriesInvalid(configFile) {
+    return getConfigFilePropertyError(configFile, DISPLAY_DEFAULT_QUERIES_PROPERTY, 'must be a boolean');
 }
-exports.getQueryUsesIncorrect = getQueryUsesIncorrect;
+exports.getDisableDefaultQueriesInvalid = getDisableDefaultQueriesInvalid;
+function getQueriesInvalid(configFile) {
+    return getConfigFilePropertyError(configFile, QUERIES_PROPERTY, 'must be an array');
+}
+exports.getQueriesInvalid = getQueriesInvalid;
+function getQueryUsesInvalid(configFile, queryUses) {
+    return getConfigFilePropertyError(configFile, QUERIES_PROPERTY + '.' + QUERIES_USES_PROPERTY, 'must be non-empty string containing either a local path starting with "./", or be of the form "owner/repo[/path]@ref"' +
+        (queryUses !== undefined ? '\n Found: ' + queryUses : ''));
+}
+exports.getQueryUsesInvalid = getQueryUsesInvalid;
+function getPathsIgnoreInvalid(configFile) {
+    return getConfigFilePropertyError(configFile, PATHS_IGNORE_PROPERTY, 'must be an array of non-empty string');
+}
+exports.getPathsIgnoreInvalid = getPathsIgnoreInvalid;
+function getPathsInvalid(configFile) {
+    return getConfigFilePropertyError(configFile, PATHS_PROPERTY, 'must be an array of non-empty string');
+}
+exports.getPathsInvalid = getPathsInvalid;
 function getConfigFileOutsideWorkspaceErrorMessage(configFile) {
     return 'The configuration file "' + configFile + '" is outside of the workspace';
 }
@@ -85,6 +108,9 @@ function getConfigFileDoesNotExistErrorMessage(configFile) {
     return 'The configuration file "' + configFile + '" does not exist';
 }
 exports.getConfigFileDoesNotExistErrorMessage = getConfigFileDoesNotExistErrorMessage;
+function getConfigFilePropertyError(configFile, property, error) {
+    return 'The configuration file "' + configFile + '" is invalid: property "' + property + '" ' + error;
+}
 function initConfig() {
     let configFile = core.getInput('config-file');
     const config = new Config();
@@ -105,34 +131,52 @@ function initConfig() {
         throw new Error(getConfigFileDoesNotExistErrorMessage(configFile));
     }
     const parsedYAML = yaml.safeLoad(fs.readFileSync(configFile, 'utf8'));
-    if (parsedYAML.name && typeof parsedYAML.name === "string") {
-        config.name = parsedYAML.name;
+    if (NAME_PROPERTY in parsedYAML) {
+        if (typeof parsedYAML[NAME_PROPERTY] !== "string") {
+            throw new Error(getNameInvalid(configFile));
+        }
+        if (parsedYAML[NAME_PROPERTY].length === 0) {
+            throw new Error(getNameInvalid(configFile));
+        }
+        config.name = parsedYAML[NAME_PROPERTY];
     }
-    if (parsedYAML['disable-default-queries'] && typeof parsedYAML['disable-default-queries'] === "boolean") {
-        config.disableDefaultQueries = parsedYAML['disable-default-queries'];
+    if (DISPLAY_DEFAULT_QUERIES_PROPERTY in parsedYAML) {
+        if (typeof parsedYAML[DISPLAY_DEFAULT_QUERIES_PROPERTY] !== "boolean") {
+            throw new Error(getDisableDefaultQueriesInvalid(configFile));
+        }
+        config.disableDefaultQueries = parsedYAML[DISPLAY_DEFAULT_QUERIES_PROPERTY];
     }
-    const queries = parsedYAML.queries;
-    if (queries && queries instanceof Array) {
-        queries.forEach(query => {
-            if (typeof query.uses === "string") {
-                config.addQuery(query.uses);
+    if (QUERIES_PROPERTY in parsedYAML) {
+        if (!(parsedYAML[QUERIES_PROPERTY] instanceof Array)) {
+            throw new Error(getQueriesInvalid(configFile));
+        }
+        parsedYAML[QUERIES_PROPERTY].forEach(query => {
+            if (!(QUERIES_USES_PROPERTY in query) || typeof query[QUERIES_USES_PROPERTY] !== "string") {
+                throw new Error(getQueryUsesInvalid(configFile));
             }
+            config.addQuery(configFile, query[QUERIES_USES_PROPERTY]);
         });
     }
-    const pathsIgnore = parsedYAML['paths-ignore'];
-    if (pathsIgnore && pathsIgnore instanceof Array) {
-        pathsIgnore.forEach(path => {
-            if (typeof path === "string") {
-                config.pathsIgnore.push(path);
+    if (PATHS_IGNORE_PROPERTY in parsedYAML) {
+        if (!(parsedYAML[PATHS_IGNORE_PROPERTY] instanceof Array)) {
+            throw new Error(getPathsIgnoreInvalid(configFile));
+        }
+        parsedYAML[PATHS_IGNORE_PROPERTY].forEach(path => {
+            if (typeof path !== "string" || path === '') {
+                throw new Error(getPathsIgnoreInvalid(configFile));
             }
+            config.pathsIgnore.push(path);
         });
     }
-    const paths = parsedYAML.paths;
-    if (paths && paths instanceof Array) {
-        paths.forEach(path => {
-            if (typeof path === "string") {
-                config.paths.push(path);
+    if (PATHS_PROPERTY in parsedYAML) {
+        if (!(parsedYAML[PATHS_PROPERTY] instanceof Array)) {
+            throw new Error(getPathsInvalid(configFile));
+        }
+        parsedYAML[PATHS_PROPERTY].forEach(path => {
+            if (typeof path !== "string" || path === '') {
+                throw new Error(getPathsInvalid(configFile));
             }
+            config.paths.push(path);
         });
     }
     return config;
diff --git a/lib/config-utils.js.map b/lib/config-utils.js.map
index 46cc1aaa6..444862b46 100644
--- a/lib/config-utils.js.map
+++ b/lib/config-utils.js.map
@@ -1 +1 @@
-{"version":3,"file":"config-utils.js","sourceRoot":"","sources":["../src/config-utils.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"config-utils.js","sourceRoot":"","sources":["../src/config-utils.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/lib/config-utils.test.js b/lib/config-utils.test.js
index 24197d574..b35069f92 100644
--- a/lib/config-utils.test.js
+++ b/lib/config-utils.test.js
@@ -109,116 +109,49 @@ ava_1.default("load non-empty input", async (t) => {
         t.deepEqual(actualConfig, expectedConfig);
     });
 });
-ava_1.default("load partially invalid input", async (t) => {
-    return await util.withTmpDir(async (tmpDir) => {
-        process.env['RUNNER_WORKSPACE'] = tmpDir;
-        process.env['GITHUB_WORKSPACE'] = tmpDir;
-        // The valid parts of this config should be parsed correctly.
-        // The invalid parts should be ignored and left as the default values.
-        const inputFileContents = `
-      name:
-        - foo: bar
-      disable-default-queries: 42
-      queries:
-        - name: foo/bar
-          uses: foo/bar@dev
-      paths-ignore:
-        - a
-        - b
-      paths:
-        - c/d`;
-        // And the config we expect it to parse to
-        const expectedConfig = new configUtils.Config();
-        expectedConfig.externalQueries = [new configUtils.ExternalQuery('foo/bar', 'dev')];
-        expectedConfig.pathsIgnore = ['a', 'b'];
-        expectedConfig.paths = ['c/d'];
-        fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
-        setInput('config-file', 'input');
-        const actualConfig = await configUtils.loadConfig();
-        // Should exactly equal the object we constructed earlier
-        t.deepEqual(actualConfig, expectedConfig);
-    });
-});
-ava_1.default("load invalid input - top level entries", async (t) => {
-    return await util.withTmpDir(async (tmpDir) => {
-        process.env['RUNNER_WORKSPACE'] = tmpDir;
-        process.env['GITHUB_WORKSPACE'] = tmpDir;
-        // Replace the arrays with strings or numbers.
-        // The invalid parts should be ignored and left as the default values.
-        const inputFileContents = `
-      name: my config
-      disable-default-queries: true
-      queries: foo
-      paths-ignore: bar
-      paths: 123`;
-        // And the config we expect it to parse to
-        const expectedConfig = new configUtils.Config();
-        expectedConfig.name = 'my config';
-        expectedConfig.disableDefaultQueries = true;
-        fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
-        setInput('config-file', 'input');
-        const actualConfig = await configUtils.loadConfig();
-        // Should exactly equal the object we constructed earlier
-        t.deepEqual(actualConfig, expectedConfig);
-    });
-});
-ava_1.default("load invalid input - queries field type", async (t) => {
-    return await util.withTmpDir(async (tmpDir) => {
-        process.env['RUNNER_WORKSPACE'] = tmpDir;
-        process.env['GITHUB_WORKSPACE'] = tmpDir;
-        // Invalid contents of the "queries" array.
-        // The invalid parts should be ignored and left as the default values.
-        const inputFileContents = `
-      name: my config
-      disable-default-queries: true
-      queries:
-        - name: foo
-          uses:
-            - hello: world
-        - name: bar
-          uses: github/bar@master`;
-        // And the config we expect it to parse to
-        const expectedConfig = new configUtils.Config();
-        expectedConfig.name = 'my config';
-        expectedConfig.disableDefaultQueries = true;
-        expectedConfig.externalQueries.push(new configUtils.ExternalQuery("github/bar", "master"));
-        fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
-        setInput('config-file', 'input');
-        const actualConfig = await configUtils.loadConfig();
-        // Should exactly equal the object we constructed earlier
-        t.deepEqual(actualConfig, expectedConfig);
-    });
-});
-// Various "uses" fields, and the errors they should produce
-const testInputs = {
-    "''": configUtils.getQueryUsesBlank(),
-    "foo/bar": configUtils.getQueryUsesIncorrect("foo/bar"),
-    "foo/bar@v1@v2": configUtils.getQueryUsesIncorrect("foo/bar@v1@v2"),
-    "foo@master": configUtils.getQueryUsesIncorrect("foo@master"),
-    "https://github.com/foo/bar@master": configUtils.getQueryUsesIncorrect("https://github.com/foo/bar@master")
-};
-for (const [input, result] of Object.entries(testInputs)) {
-    ava_1.default("load invalid input - queries uses \"" + input + "\"", async (t) => {
+function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGenerator) {
+    ava_1.default("load invalid input - " + testName, async (t) => {
         return await util.withTmpDir(async (tmpDir) => {
             process.env['RUNNER_WORKSPACE'] = tmpDir;
             process.env['GITHUB_WORKSPACE'] = tmpDir;
-            // Invalid contents of a "queries.uses" field.
-            // Should fail with the expected error message
-            const inputFileContents = `
-        name: my config
-        queries:
-          - name: foo
-            uses: ` + input;
-            fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
+            const inputFile = path.join(tmpDir, 'input');
+            fs.writeFileSync(inputFile, inputFileContents, 'utf8');
             setInput('config-file', 'input');
             try {
                 await configUtils.loadConfig();
                 throw new Error('loadConfig did not throw error');
             }
             catch (err) {
-                t.deepEqual(err, new Error(result));
+                t.deepEqual(err, new Error(expectedErrorMessageGenerator(inputFile)));
             }
         });
     });
 }
+doInvalidInputTest('name invalid type', `
+  name:
+    - foo: bar`, configUtils.getNameInvalid);
+doInvalidInputTest('disable-default-queries invalid type', `disable-default-queries: 42`, configUtils.getDisableDefaultQueriesInvalid);
+doInvalidInputTest('queries invalid type', `queries: foo`, configUtils.getQueriesInvalid);
+doInvalidInputTest('paths-ignore invalid type', `paths-ignore: bar`, configUtils.getPathsIgnoreInvalid);
+doInvalidInputTest('paths invalid type', `paths: 17`, configUtils.getPathsInvalid);
+doInvalidInputTest('queries uses invalid type', `
+  queries:
+  - uses:
+      - hello: world`, configUtils.getQueryUsesInvalid);
+function doInvalidQueryUsesTest(input, inputInErrorMessage) {
+    // Invalid contents of a "queries.uses" field.
+    // Should fail with the expected error message
+    const inputFileContents = `
+    name: my config
+    queries:
+      - name: foo
+        uses: ` + input;
+    doInvalidInputTest("queries uses \"" + input + "\"", inputFileContents, configFile => configUtils.getQueryUsesInvalid(configFile, inputInErrorMessage ? input : undefined));
+}
+// Various "uses" fields, and the errors they should produce
+doInvalidQueryUsesTest("''", false);
+doInvalidQueryUsesTest("foo/bar", true);
+doInvalidQueryUsesTest("foo/bar@v1@v2", true);
+doInvalidQueryUsesTest("foo@master", true);
+doInvalidQueryUsesTest("https://github.com/foo/bar@master", true);
 //# sourceMappingURL=config-utils.test.js.map
\ No newline at end of file
diff --git a/lib/config-utils.test.js.map b/lib/config-utils.test.js.map
index 6aa5421e0..00ae67287 100644
--- a/lib/config-utils.test.js.map
+++ b/lib/config-utils.test.js.map
@@ -1 +1 @@
-{"version":3,"file":"config-utils.test.js","sourceRoot":"","sources":["../src/config-utils.test.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"config-utils.test.js","sourceRoot":"","sources":["../src/config-utils.test.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/src/config-utils.test.ts b/src/config-utils.test.ts
index 779851118..66dc51a0f 100644
--- a/src/config-utils.test.ts
+++ b/src/config-utils.test.ts
@@ -118,136 +118,85 @@ test("load non-empty input", async t => {
   });
 });
 
-test("load partially invalid input", async t => {
-  return await util.withTmpDir(async tmpDir => {
-    process.env['RUNNER_WORKSPACE'] = tmpDir;
-    process.env['GITHUB_WORKSPACE'] = tmpDir;
-
-    // The valid parts of this config should be parsed correctly.
-    // The invalid parts should be ignored and left as the default values.
-    const inputFileContents = `
-      name:
-        - foo: bar
-      disable-default-queries: 42
-      queries:
-        - name: foo/bar
-          uses: foo/bar@dev
-      paths-ignore:
-        - a
-        - b
-      paths:
-        - c/d`;
-
-    // And the config we expect it to parse to
-    const expectedConfig = new configUtils.Config();
-    expectedConfig.externalQueries = [new configUtils.ExternalQuery('foo/bar', 'dev')];
-    expectedConfig.pathsIgnore = ['a', 'b'];
-    expectedConfig.paths = ['c/d'];
-
-    fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
-    setInput('config-file', 'input');
-
-    const actualConfig = await configUtils.loadConfig();
-
-    // Should exactly equal the object we constructed earlier
-    t.deepEqual(actualConfig, expectedConfig);
-  });
-});
-
-test("load invalid input - top level entries", async t => {
-  return await util.withTmpDir(async tmpDir => {
-    process.env['RUNNER_WORKSPACE'] = tmpDir;
-    process.env['GITHUB_WORKSPACE'] = tmpDir;
-
-    // Replace the arrays with strings or numbers.
-    // The invalid parts should be ignored and left as the default values.
-    const inputFileContents = `
-      name: my config
-      disable-default-queries: true
-      queries: foo
-      paths-ignore: bar
-      paths: 123`;
-
-    // And the config we expect it to parse to
-    const expectedConfig = new configUtils.Config();
-    expectedConfig.name = 'my config';
-    expectedConfig.disableDefaultQueries = true;
+function doInvalidInputTest(
+  testName: string,
+  inputFileContents: string,
+  expectedErrorMessageGenerator: (configFile: string) => string) {
 
-    fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
-    setInput('config-file', 'input');
-
-    const actualConfig = await configUtils.loadConfig();
-
-    // Should exactly equal the object we constructed earlier
-    t.deepEqual(actualConfig, expectedConfig);
-  });
-});
-
-test("load invalid input - queries field type", async t => {
-  return await util.withTmpDir(async tmpDir => {
-    process.env['RUNNER_WORKSPACE'] = tmpDir;
-    process.env['GITHUB_WORKSPACE'] = tmpDir;
-
-    // Invalid contents of the "queries" array.
-    // The invalid parts should be ignored and left as the default values.
-    const inputFileContents = `
-      name: my config
-      disable-default-queries: true
-      queries:
-        - name: foo
-          uses:
-            - hello: world
-        - name: bar
-          uses: github/bar@master`;
-
-    // And the config we expect it to parse to
-    const expectedConfig = new configUtils.Config();
-    expectedConfig.name = 'my config';
-    expectedConfig.disableDefaultQueries = true;
-    expectedConfig.externalQueries.push(new configUtils.ExternalQuery("github/bar", "master"));
-
-    fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
-    setInput('config-file', 'input');
-
-    const actualConfig = await configUtils.loadConfig();
-
-    // Should exactly equal the object we constructed earlier
-    t.deepEqual(actualConfig, expectedConfig);
-  });
-});
-
-// Various "uses" fields, and the errors they should produce
-const testInputs = {
-  "''": configUtils.getQueryUsesBlank(),
-  "foo/bar": configUtils.getQueryUsesIncorrect("foo/bar"),
-  "foo/bar@v1@v2": configUtils.getQueryUsesIncorrect("foo/bar@v1@v2"),
-  "foo@master": configUtils.getQueryUsesIncorrect("foo@master"),
-  "https://github.com/foo/bar@master": configUtils.getQueryUsesIncorrect("https://github.com/foo/bar@master")
-};
-
-for (const [input, result] of Object.entries(testInputs)) {
-  test("load invalid input - queries uses \"" + input + "\"", async t => {
+  test("load invalid input - " + testName, async t => {
     return await util.withTmpDir(async tmpDir => {
       process.env['RUNNER_WORKSPACE'] = tmpDir;
       process.env['GITHUB_WORKSPACE'] = tmpDir;
 
-      // Invalid contents of a "queries.uses" field.
-      // Should fail with the expected error message
-      const inputFileContents = `
-        name: my config
-        queries:
-          - name: foo
-            uses: ` + input;
-
-      fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
+      const inputFile = path.join(tmpDir, 'input');
+      fs.writeFileSync(inputFile, inputFileContents, 'utf8');
       setInput('config-file', 'input');
 
       try {
         await configUtils.loadConfig();
         throw new Error('loadConfig did not throw error');
       } catch (err) {
-        t.deepEqual(err, new Error(result));
+        t.deepEqual(err, new Error(expectedErrorMessageGenerator(inputFile)));
       }
     });
   });
 }
+
+doInvalidInputTest(
+  'name invalid type',
+  `
+  name:
+    - foo: bar`,
+  configUtils.getNameInvalid);
+
+doInvalidInputTest(
+  'disable-default-queries invalid type',
+  `disable-default-queries: 42`,
+  configUtils.getDisableDefaultQueriesInvalid);
+
+doInvalidInputTest(
+  'queries invalid type',
+  `queries: foo`,
+  configUtils.getQueriesInvalid);
+
+doInvalidInputTest(
+  'paths-ignore invalid type',
+  `paths-ignore: bar`,
+  configUtils.getPathsIgnoreInvalid);
+
+doInvalidInputTest(
+  'paths invalid type',
+  `paths: 17`,
+  configUtils.getPathsInvalid);
+
+doInvalidInputTest(
+  'queries uses invalid type',
+  `
+  queries:
+  - uses:
+      - hello: world`,
+  configUtils.getQueryUsesInvalid);
+
+function doInvalidQueryUsesTest(input: string, inputInErrorMessage: boolean) {
+  // Invalid contents of a "queries.uses" field.
+  // Should fail with the expected error message
+  const inputFileContents = `
+    name: my config
+    queries:
+      - name: foo
+        uses: ` + input;
+
+  doInvalidInputTest(
+    "queries uses \"" + input + "\"",
+    inputFileContents,
+    configFile => configUtils.getQueryUsesInvalid(
+      configFile,
+      inputInErrorMessage ? input : undefined));
+}
+
+// Various "uses" fields, and the errors they should produce
+doInvalidQueryUsesTest("''", false);
+doInvalidQueryUsesTest("foo/bar", true);
+doInvalidQueryUsesTest("foo/bar@v1@v2", true);
+doInvalidQueryUsesTest("foo@master", true);
+doInvalidQueryUsesTest("https://github.com/foo/bar@master", true);
diff --git a/src/config-utils.ts b/src/config-utils.ts
index ab2a67bb4..11a21d884 100644
--- a/src/config-utils.ts
+++ b/src/config-utils.ts
@@ -6,6 +6,13 @@ import * as path from 'path';
 
 import * as util from './util';
 
+const NAME_PROPERTY = 'name';
+const DISPLAY_DEFAULT_QUERIES_PROPERTY = 'disable-default-queries';
+const QUERIES_PROPERTY = 'queries';
+const QUERIES_USES_PROPERTY = 'uses';
+const PATHS_IGNORE_PROPERTY = 'paths-ignore';
+const PATHS_PROPERTY = 'paths';
+
 export class ExternalQuery {
     public repository: string;
     public ref: string;
@@ -25,12 +32,12 @@ export class Config {
     public pathsIgnore: string[] = [];
     public paths: string[] = [];
 
-    public addQuery(queryUses: string) {
+    public addQuery(configFile: string, queryUses: string) {
         // The logic for parsing the string is based on what actions does for
         // parsing the 'uses' actions in the workflow file
         queryUses = queryUses.trim();
         if (queryUses === "") {
-            throw new Error(getQueryUsesBlank());
+            throw new Error(getQueryUsesInvalid(configFile));
         }
 
         // Check for the local path case before we start trying to parse the repository name
@@ -41,7 +48,7 @@ export class Config {
 
         let tok = queryUses.split('@');
         if (tok.length !== 2) {
-            throw new Error(getQueryUsesIncorrect(queryUses));
+            throw new Error(getQueryUsesInvalid(configFile, queryUses));
         }
 
         const ref = tok[1];
@@ -50,7 +57,7 @@ export class Config {
         // The second token is the repo
         // The rest is a path, if there is more than one token combine them to form the full path
         if (tok.length < 2) {
-            throw new Error(getQueryUsesIncorrect(queryUses));
+            throw new Error(getQueryUsesInvalid(configFile, queryUses));
         }
         if (tok.length > 3) {
             tok = [tok[0], tok[1], tok.slice(2).join('/')];
@@ -58,7 +65,7 @@ export class Config {
 
         // Check none of the parts of the repository name are empty
         if (tok[0].trim() === '' || tok[1].trim() === '') {
-            throw new Error(getQueryUsesIncorrect(queryUses));
+            throw new Error(getQueryUsesInvalid(configFile, queryUses));
         }
 
         let external = new ExternalQuery(tok[0] + '/' + tok[1], ref);
@@ -69,12 +76,32 @@ export class Config {
     }
 }
 
-export function getQueryUsesBlank(): string {
-    return '"uses" value for queries cannot be blank';
+export function getNameInvalid(configFile: string): string {
+    return getConfigFilePropertyError(configFile, NAME_PROPERTY, 'must be a non-empty string');
+}
+
+export function getDisableDefaultQueriesInvalid(configFile: string): string {
+    return getConfigFilePropertyError(configFile, DISPLAY_DEFAULT_QUERIES_PROPERTY, 'must be a boolean');
+}
+
+export function getQueriesInvalid(configFile: string): string {
+    return getConfigFilePropertyError(configFile, QUERIES_PROPERTY, 'must be an array');
+}
+
+export function getQueryUsesInvalid(configFile: string, queryUses?: string): string {
+    return getConfigFilePropertyError(
+        configFile,
+        QUERIES_PROPERTY + '.' + QUERIES_USES_PROPERTY,
+        'must be non-empty string containing either a local path starting with "./", or be of the form "owner/repo[/path]@ref"' +
+            (queryUses !== undefined ? '\n Found: ' + queryUses : ''));
+}
+
+export function getPathsIgnoreInvalid(configFile: string): string {
+    return getConfigFilePropertyError(configFile, PATHS_IGNORE_PROPERTY, 'must be an array of non-empty string');
 }
 
-export function getQueryUsesIncorrect(queryUses: string): string {
-    return '"uses" value for queries must be a path, or owner/repo@ref \n Found: ' + queryUses;
+export function getPathsInvalid(configFile: string): string {
+    return getConfigFilePropertyError(configFile, PATHS_PROPERTY, 'must be an array of non-empty string');
 }
 
 export function getConfigFileOutsideWorkspaceErrorMessage(configFile: string): string {
@@ -85,6 +112,10 @@ export function getConfigFileDoesNotExistErrorMessage(configFile: string): strin
     return 'The configuration file "' + configFile + '" does not exist';
 }
 
+function getConfigFilePropertyError(configFile: string, property: string, error: string): string {
+    return 'The configuration file "' + configFile + '" is invalid: property "' + property + '" ' + error;
+}
+
 function initConfig(): Config {
     let configFile = core.getInput('config-file');
 
@@ -112,38 +143,56 @@ function initConfig(): Config {
 
     const parsedYAML = yaml.safeLoad(fs.readFileSync(configFile, 'utf8'));
 
-    if (parsedYAML.name && typeof parsedYAML.name === "string") {
-        config.name = parsedYAML.name;
+    if (NAME_PROPERTY in parsedYAML) {
+        if (typeof parsedYAML[NAME_PROPERTY] !== "string") {
+            throw new Error(getNameInvalid(configFile));
+        }
+        if (parsedYAML[NAME_PROPERTY].length === 0) {
+            throw new Error(getNameInvalid(configFile));
+        }
+        config.name = parsedYAML[NAME_PROPERTY];
     }
 
-    if (parsedYAML['disable-default-queries'] && typeof parsedYAML['disable-default-queries'] === "boolean") {
-        config.disableDefaultQueries = parsedYAML['disable-default-queries'];
+    if (DISPLAY_DEFAULT_QUERIES_PROPERTY in parsedYAML) {
+        if (typeof parsedYAML[DISPLAY_DEFAULT_QUERIES_PROPERTY] !== "boolean") {
+            throw new Error(getDisableDefaultQueriesInvalid(configFile));
+        }
+        config.disableDefaultQueries = parsedYAML[DISPLAY_DEFAULT_QUERIES_PROPERTY];
     }
 
-    const queries = parsedYAML.queries;
-    if (queries && queries instanceof Array) {
-        queries.forEach(query => {
-            if (typeof query.uses === "string") {
-                config.addQuery(query.uses);
+    if (QUERIES_PROPERTY in parsedYAML) {
+        if (!(parsedYAML[QUERIES_PROPERTY] instanceof Array)) {
+            throw new Error(getQueriesInvalid(configFile));
+        }
+        parsedYAML[QUERIES_PROPERTY].forEach(query => {
+            if (!(QUERIES_USES_PROPERTY in query) || typeof query[QUERIES_USES_PROPERTY] !== "string") {
+                throw new Error(getQueryUsesInvalid(configFile));
             }
+            config.addQuery(configFile, query[QUERIES_USES_PROPERTY]);
         });
     }
 
-    const pathsIgnore = parsedYAML['paths-ignore'];
-    if (pathsIgnore && pathsIgnore instanceof Array) {
-        pathsIgnore.forEach(path => {
-            if (typeof path === "string") {
-                config.pathsIgnore.push(path);
+    if (PATHS_IGNORE_PROPERTY in parsedYAML) {
+        if (!(parsedYAML[PATHS_IGNORE_PROPERTY] instanceof Array)) {
+            throw new Error(getPathsIgnoreInvalid(configFile));
+        }
+        parsedYAML[PATHS_IGNORE_PROPERTY].forEach(path => {
+            if (typeof path !== "string" || path === '') {
+                throw new Error(getPathsIgnoreInvalid(configFile));
             }
+            config.pathsIgnore.push(path);
         });
     }
 
-    const paths = parsedYAML.paths;
-    if (paths && paths instanceof Array) {
-        paths.forEach(path => {
-            if (typeof path === "string") {
-                config.paths.push(path);
+    if (PATHS_PROPERTY in parsedYAML) {
+        if (!(parsedYAML[PATHS_PROPERTY] instanceof Array)) {
+            throw new Error(getPathsInvalid(configFile));
+        }
+        parsedYAML[PATHS_PROPERTY].forEach(path => {
+            if (typeof path !== "string" || path === '') {
+                throw new Error(getPathsInvalid(configFile));
             }
+            config.paths.push(path);
         });
     }