Skip to content
This repository was archived by the owner on May 15, 2025. It is now read-only.

Commit 36fa871

Browse files
committed
add tests
1 parent 46bf422 commit 36fa871

File tree

6 files changed

+139
-21
lines changed

6 files changed

+139
-21
lines changed

CONTRIBUTING.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ To create a new module, clone this repository and run:
1010

1111
A suite of test-helpers exists to run `terraform apply` on modules with variables, and test script output against containers.
1212

13+
The testing suite must be able to run docker containers with the `--network=host` flag, which typically requires running the tests on linux as this flag does not apply to Docker Desktop for MacOS and Windows. MacOS users can work around this by using something like [Orbstack](https://orbstack.dev/) instead of Docker Desktop.
14+
1315
Reference existing `*.test.ts` files for implementation.
1416

1517
```shell

github-upload-public-key/main.test.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { describe, expect, it } from "bun:test";
2+
import { createJSONResponse, execContainer, findResourceInstance, runContainer, runTerraformApply, runTerraformInit, testRequiredVariables, writeCoder } from "../test";
3+
import { Server, serve } from "bun";
4+
5+
describe("github-upload-public-key", async () => {
6+
await runTerraformInit(import.meta.dir);
7+
8+
testRequiredVariables(import.meta.dir, {
9+
agent_id: "foo",
10+
});
11+
12+
it("creates new key if one does not exist", async () => {
13+
const { instance, id } = await setupContainer();
14+
await writeCoder(id, "echo foo");
15+
let exec = await execContainer(id, ["bash", "-c", instance.script]);
16+
expect(exec.stdout).toContain("Coder public SSH key uploaded to GitHub!")
17+
expect(exec.exitCode).toBe(0);
18+
});
19+
20+
it("does nothing if one already exists", async () => {
21+
const { instance, id } = await setupContainer();
22+
await writeCoder(id, "echo findkey");
23+
let exec = await execContainer(id, ["bash", "-c", instance.script]);
24+
expect(exec.stdout).toContain("Coder public SSH key is already uploaded to GitHub!")
25+
expect(exec.exitCode).toBe(0);
26+
});
27+
});
28+
29+
const setupContainer = async (
30+
image = "lorello/alpine-bash",
31+
vars: Record<string, string> = {},
32+
) => {
33+
const server = await setupServer();
34+
const state = await runTerraformApply(import.meta.dir, {
35+
agent_id: "foo",
36+
// trim the trailing slash on the URL
37+
access_url: server.url.toString().slice(0, -1),
38+
owner_session_token: "bar",
39+
github_api_url: server.url.toString().slice(0, -1),
40+
...vars,
41+
});
42+
const instance = findResourceInstance(state, "coder_script");
43+
const id = await runContainer(image);
44+
return { id, instance };
45+
};
46+
47+
const setupServer = async (): Promise<Server> => {
48+
let url: URL;
49+
const fakeSlackHost = serve({
50+
fetch: (req) => {
51+
url = new URL(req.url);
52+
if (url.pathname === "/api/v2/users/me/gitsshkey") {
53+
return createJSONResponse({
54+
public_key: "exists",
55+
});
56+
}
57+
58+
if (url.pathname === "/user/keys") {
59+
if (req.method === "POST") {
60+
return createJSONResponse({
61+
key: "created",
62+
}, 201);
63+
}
64+
65+
// case: key already exists
66+
if (req.headers.get("Authorization") == "Bearer findkey") {
67+
return createJSONResponse([{
68+
key: "foo",
69+
}, {
70+
key: "exists",
71+
}]);
72+
}
73+
74+
// case: key does not exist
75+
return createJSONResponse([{
76+
key: "foo",
77+
}]);
78+
}
79+
80+
81+
return createJSONResponse({
82+
error: "not_found"
83+
}, 404);
84+
},
85+
port: 0,
86+
});
87+
88+
return fakeSlackHost;
89+
}

github-upload-public-key/main.tf

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,34 @@ variable "external_auth_id" {
2020
default = "github"
2121
}
2222

23+
variable "github_api_url" {
24+
type = string
25+
description = "The URL of the GitHub instance."
26+
default = "https://api.github.com"
27+
}
28+
29+
// Optional variables mostly for testing purposes, will normally come from data.coder_workspace.me
30+
variable "access_url" {
31+
type = string
32+
description = "The access URL of the workspace."
33+
default = ""
34+
}
35+
36+
variable "owner_session_token" {
37+
type = string
38+
description = "The owner session token of the workspace."
39+
default = ""
40+
}
41+
2342
data "coder_workspace" "me" {}
2443

2544
resource "coder_script" "github_upload_public_key" {
2645
agent_id = var.agent_id
2746
script = templatefile("${path.module}/run.sh", {
28-
CODER_OWNER_SESSION_TOKEN : data.coder_workspace.me.owner_session_token,
29-
CODER_ACCESS_URL : data.coder_workspace.me.access_url,
30-
GITHUB_EXTERNAL_AUTH_ID : var.external_auth_id,
47+
CODER_OWNER_SESSION_TOKEN : var.owner_session_token != "" ? var.owner_session_token : data.coder_workspace.me.owner_session_token,
48+
CODER_ACCESS_URL : var.access_url != "" ? var.access_url : data.coder_workspace.me.access_url,
49+
CODER_EXTERNAL_AUTH_ID : var.external_auth_id,
50+
GITHUB_API_URL : var.github_api_url,
3151
})
3252
display_name = "Github Upload Public Key"
3353
icon = "/icon/github.svg"

github-upload-public-key/run.sh

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ set -e
44

55
CODER_ACCESS_URL="${CODER_ACCESS_URL}"
66
CODER_OWNER_SESSION_TOKEN="${CODER_OWNER_SESSION_TOKEN}"
7-
GITHUB_EXTERNAL_AUTH_ID="${GITHUB_EXTERNAL_AUTH_ID}"
7+
CODER_EXTERNAL_AUTH_ID="${CODER_EXTERNAL_AUTH_ID}"
8+
GITHUB_API_URL="${GITHUB_API_URL}"
89

910
if [ -z "$CODER_ACCESS_URL" ]; then
1011
echo "No coder access url specified!"
@@ -16,13 +17,18 @@ if [ -z "$CODER_OWNER_SESSION_TOKEN" ]; then
1617
exit 1
1718
fi
1819

19-
if [ -z "$GITHUB_EXTERNAL_AUTH_ID" ]; then
20+
if [ -z "$CODER_EXTERNAL_AUTH_ID" ]; then
2021
echo "No GitHub external auth id specified!"
2122
exit 1
2223
fi
2324

25+
if [ -z "$GITHUB_API_URL" ]; then
26+
echo "No GitHub API URL specified!"
27+
exit 1
28+
fi
29+
2430
echo "Fetching GitHub token..."
25-
GITHUB_TOKEN=$(coder external-auth access-token $GITHUB_EXTERNAL_AUTH_ID)
31+
GITHUB_TOKEN=$(coder external-auth access-token $CODER_EXTERNAL_AUTH_ID)
2632
if [ $? -ne 0 ]; then
2733
echo "Failed to fetch GitHub token!"
2834
exit 1
@@ -36,7 +42,7 @@ echo "GitHub token found!"
3642
echo "Fetching Coder public SSH key..."
3743
PUBLIC_KEY_RESPONSE=$(
3844
curl -L -s \
39-
-w "%%{http_code}" \
45+
-w "\n%%{http_code}" \
4046
-H 'accept: application/json' \
4147
-H "cookie: coder_session_token=$CODER_OWNER_SESSION_TOKEN" \
4248
"$CODER_ACCESS_URL/api/v2/users/me/gitsshkey"
@@ -61,11 +67,11 @@ fi
6167
echo "Fetching GitHub public SSH keys..."
6268
GITHUB_KEYS_RESPONSE=$(
6369
curl -L -s \
64-
-w "%%{http_code}" \
70+
-w "\n%%{http_code}" \
6571
-H "Accept: application/vnd.github+json" \
6672
-H "Authorization: Bearer $GITHUB_TOKEN" \
6773
-H "X-GitHub-Api-Version: 2022-11-28" \
68-
https://api.github.com/user/keys
74+
$GITHUB_API_URL/user/keys
6975
)
7076
GITHUB_KEYS_RESPONSE_STATUS=$(tail -n1 <<< "$GITHUB_KEYS_RESPONSE")
7177
GITHUB_KEYS_RESPONSE_BODY=$(sed \$d <<< "$GITHUB_KEYS_RESPONSE")
@@ -89,11 +95,11 @@ CODER_PUBLIC_KEY_NAME="$CODER_ACCESS_URL Workspaces"
8995
UPLOAD_RESPONSE=$(
9096
curl -L -s \
9197
-X POST \
92-
-w "%%{http_code}" \
98+
-w "\n%%{http_code}" \
9399
-H "Accept: application/vnd.github+json" \
94100
-H "Authorization: Bearer $GITHUB_TOKEN" \
95101
-H "X-GitHub-Api-Version: 2022-11-28" \
96-
https://api.github.com/user/keys \
102+
$GITHUB_API_URL/user/keys \
97103
-d "{\"title\":\"$CODER_PUBLIC_KEY_NAME\",\"key\":\"$PUBLIC_KEY\"}"
98104
)
99105
UPLOAD_RESPONSE_STATUS=$(tail -n1 <<< "$UPLOAD_RESPONSE")

slackme/main.test.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
runTerraformApply,
99
runTerraformInit,
1010
testRequiredVariables,
11+
writeCoder,
1112
} from "../test";
1213

1314
describe("slackme", async () => {
@@ -119,15 +120,6 @@ const setupContainer = async (
119120
return { id, instance };
120121
};
121122

122-
const writeCoder = async (id: string, script: string) => {
123-
const exec = await execContainer(id, [
124-
"sh",
125-
"-c",
126-
`echo '${script}' > /usr/bin/coder && chmod +x /usr/bin/coder`,
127-
]);
128-
expect(exec.exitCode).toBe(0);
129-
};
130-
131123
const assertSlackMessage = async (opts: {
132124
command: string;
133125
format?: string;

test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,13 @@ export const createJSONResponse = (obj: object, statusCode = 200): Response => {
222222
},
223223
status: statusCode,
224224
})
225-
}
225+
}
226+
227+
export const writeCoder = async (id: string, script: string) => {
228+
const exec = await execContainer(id, [
229+
"sh",
230+
"-c",
231+
`echo '${script}' > /usr/bin/coder && chmod +x /usr/bin/coder`,
232+
]);
233+
expect(exec.exitCode).toBe(0);
234+
};

0 commit comments

Comments
 (0)