fix: avoid erroring if conflicting techniques are set from environment variables (#374)

This commit is contained in:
Eden Zimbelman
2024-12-04 20:32:13 -08:00
committed by GitHub
parent c77439f673
commit 4879c43335
5 changed files with 77 additions and 21 deletions
+24 -17
View File
@@ -110,16 +110,32 @@ export default class Config {
core.getInput("webhook") || process.env.SLACK_WEBHOOK_URL || null, core.getInput("webhook") || process.env.SLACK_WEBHOOK_URL || null,
webhookType: core.getInput("webhook-type"), webhookType: core.getInput("webhook-type"),
}; };
this.validate(); this.mask();
this.validate(core);
core.debug(`Gathered action inputs: ${JSON.stringify(this.inputs)}`); core.debug(`Gathered action inputs: ${JSON.stringify(this.inputs)}`);
this.content = new Content().get(this); this.content = new Content().get(this);
core.debug(`Parsed request content: ${JSON.stringify(this.content)}`); core.debug(`Parsed request content: ${JSON.stringify(this.content)}`);
} }
/** /**
* Confirm the configurations are correct enough to continue. * Hide secret values provided in the inputs from appearing.
*/ */
validate() { mask() {
if (this.inputs.token) {
core.debug("Setting the provided token as a secret variable.");
core.setSecret(this.inputs.token);
}
if (this.inputs.webhook) {
core.debug("Setting the provided webhook as a secret variable.");
core.setSecret(this.inputs.webhook);
}
}
/**
* Confirm the configurations are correct enough to continue.
* @param {core} core - GitHub Actions core utilities.
*/
validate(core) {
switch (this.inputs.retries.trim().toUpperCase()) { switch (this.inputs.retries.trim().toUpperCase()) {
case this.Retries.ZERO: case this.Retries.ZERO:
case this.Retries.FIVE: case this.Retries.FIVE:
@@ -133,29 +149,20 @@ export default class Config {
); );
} }
switch (true) { switch (true) {
case !!this.inputs.token && !!this.inputs.webhook: case !!core.getInput("token") && !!core.getInput("webhook"):
core.debug(
"Setting the provided token and webhook as secret variables.",
);
core.setSecret(this.inputs.token);
core.setSecret(this.inputs.webhook);
throw new SlackError( throw new SlackError(
core, core,
"Invalid input! Either the token or webhook is required - not both.", "Invalid input! Either the token or webhook is required - not both.",
); );
case !!this.inputs.token: case !!this.inputs.method:
core.debug("Setting the provided token as a secret variable."); if (!this.inputs.token) {
core.setSecret(this.inputs.token);
if (!this.inputs.method) {
throw new SlackError( throw new SlackError(
core, core,
"Missing input! A method must be decided to use the token provided.", "Missing input! A token must be provided to use the method decided.",
); );
} }
break; break;
case !!this.inputs.webhook: case !!this.inputs.webhook:
core.debug("Setting the provided webhook as a secret variable.");
core.setSecret(this.inputs.webhook);
if (!this.inputs.webhookType) { if (!this.inputs.webhookType) {
throw new SlackError( throw new SlackError(
core, core,
@@ -175,7 +182,7 @@ export default class Config {
default: default:
throw new SlackError( throw new SlackError(
core, core,
"Missing input! Either a token or webhook is required to take action.", "Missing input! Either a method or webhook is required to take action.",
); );
} }
} }
+1 -1
View File
@@ -29,7 +29,7 @@ export default async function send(core) {
*/ */
async function post(config) { async function post(config) {
switch (true) { switch (true) {
case !!config.inputs.token: case !!config.inputs.method:
return await new Client().post(config); return await new Client().post(config);
case !!config.inputs.webhook: case !!config.inputs.webhook:
return await new Webhook().post(config); return await new Webhook().post(config);
+48 -3
View File
@@ -32,12 +32,40 @@ describe("config", () => {
assert.equal(config.inputs.proxy, "https://example.com"); assert.equal(config.inputs.proxy, "https://example.com");
assert.equal(config.inputs.retries, config.Retries.ZERO); assert.equal(config.inputs.retries, config.Retries.ZERO);
assert.equal(config.inputs.token, "xoxb-example"); assert.equal(config.inputs.token, "xoxb-example");
assert.isTrue(mocks.core.setSecret.withArgs("xoxb-example").called);
});
it("allows token environment variables with a webhook", async () => {
process.env.SLACK_TOKEN = "xoxb-example";
mocks.core.getInput.withArgs("webhook").returns("https://example.com");
mocks.core.getInput.withArgs("webhook-type").returns("incoming-webhook");
const config = new Config(mocks.core);
assert.equal(config.inputs.token, "xoxb-example");
assert.equal(config.inputs.webhook, "https://example.com");
assert.equal(config.inputs.webhookType, "incoming-webhook");
assert.isTrue(mocks.core.setSecret.withArgs("xoxb-example").called);
assert.isTrue(
mocks.core.setSecret.withArgs("https://example.com").called,
);
});
it("allows webhook environment variables with a token", async () => {
process.env.SLACK_WEBHOOK_URL = "https://example.com";
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
mocks.core.getInput.withArgs("token").returns("xoxb-example");
const config = new Config(mocks.core);
assert.equal(config.inputs.method, "chat.postMessage");
assert.equal(config.inputs.token, "xoxb-example");
assert.equal(config.inputs.webhook, "https://example.com");
assert.isTrue(mocks.core.setSecret.withArgs("xoxb-example").called);
assert.isTrue(
mocks.core.setSecret.withArgs("https://example.com").called,
);
}); });
it("errors when both the token and webhook is provided", async () => { it("errors when both the token and webhook is provided", async () => {
mocks.core.getInput.withArgs("token").returns("xoxb-example"); mocks.core.getInput.withArgs("token").returns("xoxb-example");
mocks.core.getInput.withArgs("webhook").returns("https://example.com"); mocks.core.getInput.withArgs("webhook").returns("https://example.com");
mocks.core.getInput.withArgs("webhook-type").returns("incoming-webhook");
try { try {
new Config(mocks.core); new Config(mocks.core);
assert.fail("Failed to error when invalid inputs are provided"); assert.fail("Failed to error when invalid inputs are provided");
@@ -57,6 +85,23 @@ describe("config", () => {
} }
}); });
it("errors if the method is provided without a token", async () => {
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
try {
new Config(mocks.core);
assert.fail("Failed to error when invalid inputs are provided");
} catch (err) {
if (err instanceof SlackError) {
assert.include(
err.message,
"Missing input! A token must be provided to use the method decided.",
);
} else {
assert.fail("Failed to throw a SlackError", err);
}
}
});
it("errors if neither the token or webhook is provided", async () => { it("errors if neither the token or webhook is provided", async () => {
try { try {
new Config(mocks.core); new Config(mocks.core);
@@ -65,7 +110,7 @@ describe("config", () => {
if (err instanceof SlackError) { if (err instanceof SlackError) {
assert.include( assert.include(
err.message, err.message,
"Missing input! Either a token or webhook is required to take action.", "Missing input! Either a method or webhook is required to take action.",
); );
} else { } else {
assert.fail("Failed to throw a SlackError", err); assert.fail("Failed to throw a SlackError", err);
@@ -109,7 +154,7 @@ describe("config", () => {
}); });
}); });
describe("secrets", async () => { describe("mask", async () => {
it("treats the provided token as a secret", async () => { it("treats the provided token as a secret", async () => {
mocks.core.getInput.withArgs("token").returns("xoxb-example"); mocks.core.getInput.withArgs("token").returns("xoxb-example");
try { try {
+2
View File
@@ -61,6 +61,8 @@ export class Mock {
this.core.getInput.reset(); this.core.getInput.reset();
this.core.getInput.withArgs("errors").returns("false"); this.core.getInput.withArgs("errors").returns("false");
this.core.getInput.withArgs("retries").returns("5"); this.core.getInput.withArgs("retries").returns("5");
process.env.SLACK_TOKEN = "";
process.env.SLACK_WEBHOOK_URL = "";
} }
} }
+2
View File
@@ -39,6 +39,7 @@ describe("send", () => {
}); });
it("token", async () => { it("token", async () => {
process.env.SLACK_WEBHOOK_URL = "https://example.com"; // https://github.com/slackapi/slack-github-action/issues/373
mocks.api.resolves({ ok: true }); mocks.api.resolves({ ok: true });
mocks.core.getInput.withArgs("method").returns("chat.postMessage"); mocks.core.getInput.withArgs("method").returns("chat.postMessage");
mocks.core.getInput.withArgs("token").returns("xoxb-example"); mocks.core.getInput.withArgs("token").returns("xoxb-example");
@@ -56,6 +57,7 @@ describe("send", () => {
}); });
it("incoming webhook", async () => { it("incoming webhook", async () => {
process.env.SLACK_TOKEN = "xoxb-example"; // https://github.com/slackapi/slack-github-action/issues/373
mocks.core.getInput mocks.core.getInput
.withArgs("webhook") .withArgs("webhook")
.returns("https://hooks.slack.com"); .returns("https://hooks.slack.com");