Skip to content

Commit

Permalink
refactor: Refactor verify-token validation (#1660)
Browse files Browse the repository at this point in the history
- Fixes #1410
- Fixes #1411
- Fixes #1643 

Various refactors to verify-token

- Removes the call to getWorkflowRun API
- Refactors and cleans up validation code in `verify-token`.
- Improves the GitHub values included in the token in `setup-token` and validation of those values in `verify-token`.
- Adds some unit tests to the `verify-token` action.

Signed-off-by: Ian Lewis ianlewis@google.com
  • Loading branch information
ianlewis authored Feb 24, 2023
1 parent 9a60e24 commit 4ed6a51
Show file tree
Hide file tree
Showing 19 changed files with 24,314 additions and 25,317 deletions.
4 changes: 4 additions & 0 deletions .github/actions/verify-token/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ clean:
## Testing
#####################################################################

.PHONY: unit-test
unit-test: node_modules/.installed ## Runs all unit tests.
npm run test

.PHONY: lint
lint: node_modules/.installed ## Runs eslint.
npm run format-check
Expand Down
55 changes: 55 additions & 0 deletions .github/actions/verify-token/__tests__/predicate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* @fileoverview Tests for predicate.ts
*/

import { getWorkflowPath } from "../src/predicate";
import { githubObj } from "../src/types";

describe("getWorkflowPath", () => {
it("extracts path from workflow ref", () => {
const obj: githubObj = {
actor_id: "",
event_name: "",
event_path: "",
job: "",
ref: "",
ref_type: "",
repository: "octocat/hello-world",
repository_id: "",
repository_owner_id: "",
run_attempt: "",
run_id: "",
run_number: "",
sha: "",
workflow_ref:
"octocat/hello-world/.github/workflows/my-workflow.yml@refs/heads/my_branch",
workflow_sha: "",
};

const path = getWorkflowPath(obj);
expect(path).toEqual(".github/workflows/my-workflow.yml");
});

it("extracts path from workflow ref without git ref", () => {
const obj: githubObj = {
actor_id: "",
event_name: "",
event_path: "",
job: "",
ref: "",
ref_type: "",
repository: "octocat/hello-world",
repository_id: "",
repository_owner_id: "",
run_attempt: "",
run_id: "",
run_number: "",
sha: "",
workflow_ref: "octocat/hello-world/.github/workflows/my-workflow.yml",
workflow_sha: "",
};

const path = getWorkflowPath(obj);
expect(path).toEqual(".github/workflows/my-workflow.yml");
});
});
249 changes: 249 additions & 0 deletions .github/actions/verify-token/__tests__/validate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
/**
* @fileoverview Tests for predicate.ts
*/

import {
validateField,
validateFieldAnyOf,
validateFieldNonEmpty,
validateGitHubFields,
} from "../src/validate";
import { githubObj } from "../src/types";

describe("validateField", () => {
it("validates equal values", () => {
validateField("foo", "foo", "foo");
});

it("does not validate unequal values", () => {
expect(() => {
validateField("foo", "foo", "bar");
}).toThrow();

expect(() => {
validateField("foo", "bar", "foo");
}).toThrow();
});

it("does not validate unequal types", () => {
expect(() => {
validateField("foo", null, undefined);
}).toThrow();

expect(() => {
validateField("foo", "", undefined);
}).toThrow();

expect(() => {
validateField("foo", "undefined", undefined);
}).toThrow();

expect(() => {
validateField("foo", "", null);
}).toThrow();

expect(() => {
validateField("foo", "null", null);
}).toThrow();
});

it("does not validate equal empty values", () => {
expect(() => {
validateField("foo", "", "");
}).toThrow();

expect(() => {
validateField("foo", undefined, undefined);
}).toThrow();

expect(() => {
validateField("foo", null, null);
}).toThrow();
});
});

describe("validateFieldAnyOf", () => {
it("validates from a single choice", () => {
validateFieldAnyOf("foo", "foo", ["foo"]);
});

it("validates from a multiple choices", () => {
validateFieldAnyOf("foo", "foo", ["bar", "foo"]);
});

it("does not validate from unequal choices", () => {
expect(() => {
validateFieldAnyOf("foo", "foo", ["bar", "baz"]);
}).toThrow();
});

it("does not validate from no choices", () => {
expect(() => {
validateFieldAnyOf("foo", "foo", []);
}).toThrow();
});

it("does not validate from unequal types", () => {
expect(() => {
validateFieldAnyOf("foo", "", [null, undefined]);
}).toThrow();

expect(() => {
validateFieldAnyOf("foo", "null", [null]);
}).toThrow();

expect(() => {
validateFieldAnyOf("foo", "undefined", [undefined]);
}).toThrow();
});
});

describe("validateFieldNonEmpty", () => {
it("validates from a non-empty value", () => {
validateFieldNonEmpty("foo", "foo");
validateFieldNonEmpty("foo", "0");
validateFieldNonEmpty("foo", "null");
validateFieldNonEmpty("foo", "undefined");
});

it("does not validate empty value", () => {
expect(() => {
validateFieldNonEmpty("foo", "");
}).toThrow();
});
});

describe("validateGitHubFields", () => {
const env = process.env;

beforeEach(() => {
jest.resetModules();
process.env = { ...env };
});

afterEach(() => {
process.env = env;
});

it("validates from githubObj", () => {
process.env.GITHUB_ACTOR_ID = "123";
process.env.GITHUB_EVENT_NAME = "workflow_dispatch";
process.env.GITHUB_EVENT_PATH = "/path/to/event.json";
process.env.GITHUB_JOB = "234";
process.env.GITHUB_REF = "refs/heads/mybranch";
process.env.GITHUB_REF_TYPE = "branch";
process.env.GITHUB_REPOSITORY = "ianlewis/byob-test";
process.env.GITHUB_REPOSITORY_ID = "456";
process.env.GITHUB_REPOSITORY_OWNER_ID = "789";
process.env.GITHUB_RUN_ATTEMPT = "1";
process.env.GITHUB_RUN_ID = "123456789";
process.env.GITHUB_RUN_NUMBER = "1";
process.env.GITHUB_SHA = "deadbeef";
process.env.GITHUB_WORKFLOW_REF =
"ianlewis/byob-test/.github/workflows/my-workflow.yml@refs/heads/my_branch";
process.env.GITHUB_WORKFLOW_SHA = "deadbeef";

const obj: githubObj = {
actor_id: "123",
event_name: "workflow_dispatch",
event_path: "/path/to/event.json",
job: "234",
ref: "refs/heads/mybranch",
ref_type: "branch",
repository: "ianlewis/byob-test",
repository_id: "456",
repository_owner_id: "789",
run_attempt: "1",
run_id: "123456789",
run_number: "1",
sha: "deadbeef",
workflow_ref:
"ianlewis/byob-test/.github/workflows/my-workflow.yml@refs/heads/my_branch",
workflow_sha: "deadbeef",
};
validateGitHubFields(obj);
});

it("does not validate githubObj with empty fields", () => {
process.env.GITHUB_ACTOR_ID = "123";
process.env.GITHUB_EVENT_NAME = "workflow_dispatch";
process.env.GITHUB_EVENT_PATH = "/path/to/event.json";
process.env.GITHUB_JOB = "234";
process.env.GITHUB_REF = "refs/heads/mybranch";
process.env.GITHUB_REF_TYPE = "branch";
process.env.GITHUB_REPOSITORY = "ianlewis/byob-test";
process.env.GITHUB_REPOSITORY_ID = "";
process.env.GITHUB_REPOSITORY_OWNER_ID = "789";
process.env.GITHUB_RUN_ATTEMPT = "1";
process.env.GITHUB_RUN_ID = "123456789";
process.env.GITHUB_RUN_NUMBER = "1";
process.env.GITHUB_SHA = "deadbeef";
process.env.GITHUB_WORKFLOW_REF =
"ianlewis/byob-test/.github/workflows/my-workflow.yml@refs/heads/my_branch";
process.env.GITHUB_WORKFLOW_SHA = "deadbeef";

const obj: githubObj = {
actor_id: "123",
event_name: "workflow_dispatch",
event_path: "/path/to/event.json",
job: "234",
ref: "refs/heads/mybranch",
ref_type: "branch",
repository: "ianlewis/byob-test",
repository_id: "", // NOTE: Empty
repository_owner_id: "789",
run_attempt: "1",
run_id: "123456789",
run_number: "1",
sha: "deadbeef",
workflow_ref:
"ianlewis/byob-test/.github/workflows/my-workflow.yml@refs/heads/my_branch",
workflow_sha: "deadbeef",
};
expect(() => {
validateGitHubFields(obj);
}).toThrow();
});

it("does not validate githubObj with unequal fields", () => {
process.env.GITHUB_ACTOR_ID = "123";
process.env.GITHUB_EVENT_NAME = "workflow_dispatch";
process.env.GITHUB_EVENT_PATH = "/path/to/event.json";
process.env.GITHUB_JOB = "234";
process.env.GITHUB_REF = "refs/heads/mybranch";
process.env.GITHUB_REF_TYPE = "branch";
process.env.GITHUB_REPOSITORY = "ianlewis/byob-test";
process.env.GITHUB_REPOSITORY_ID = "456";
process.env.GITHUB_REPOSITORY_OWNER_ID = "789";
process.env.GITHUB_RUN_ATTEMPT = "1";
process.env.GITHUB_RUN_ID = "123456789";
process.env.GITHUB_RUN_NUMBER = "1";
process.env.GITHUB_SHA = "deadbeef";
process.env.GITHUB_WORKFLOW = ".github/workflow/myworkflow.yml";
process.env.GITHUB_WORKFLOW_REF =
"ianlewis/byob-test/.github/workflows/my-workflow.yml@refs/heads/my_branch";
process.env.GITHUB_WORKFLOW_SHA = "deadbeef";

const obj: githubObj = {
actor_id: "123",
event_name: "workflow_dispatch",
event_path: "/path/to/event.json",
job: "234",
ref: "refs/heads/mybranch",
ref_type: "branch",
repository: "asraa/byob-test", // NOTE: Not equal
repository_id: "456",
repository_owner_id: "789",
run_attempt: "1",
run_id: "123456789",
run_number: "1",
sha: "deadbeef",
workflow_ref:
"ianlewis/byob-test/.github/workflows/my-workflow.yml@refs/heads/my_branch",
workflow_sha: "deadbeef",
};
expect(() => {
validateGitHubFields(obj);
}).toThrow();
});
});
Loading

0 comments on commit 4ed6a51

Please sign in to comment.