95 lines
3.5 KiB
JavaScript
95 lines
3.5 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const repoRoot = path.resolve(
|
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
"..",
|
|
);
|
|
const workflowPath = path.join(
|
|
repoRoot,
|
|
".github/workflows/notify-docs.yml",
|
|
);
|
|
|
|
function extractJob(workflow, name) {
|
|
const marker = ` ${name}:\n`;
|
|
const start = workflow.indexOf(marker);
|
|
assert.notEqual(start, -1, `workflow job not found: ${name}`);
|
|
|
|
const bodyStart = start + marker.length;
|
|
const remainder = workflow.slice(bodyStart);
|
|
const nextJob = remainder.search(/\n [a-z0-9-]+:\n/);
|
|
return remainder.slice(0, nextJob === -1 ? remainder.length : nextJob);
|
|
}
|
|
|
|
function extractStep(job, name) {
|
|
const marker = ` - name: ${name}\n`;
|
|
const start = job.indexOf(marker);
|
|
assert.notEqual(start, -1, `workflow step not found: ${name}`);
|
|
|
|
const bodyStart = start + marker.length;
|
|
const remainder = job.slice(bodyStart);
|
|
const nextStep = remainder.search(/\n - name: /);
|
|
return remainder.slice(0, nextStep === -1 ? remainder.length : nextStep);
|
|
}
|
|
|
|
const tokenExpression = String.raw`\$\{\{ secrets\.GITHUB_TOKEN \}\}`;
|
|
|
|
test("docs preview build uses an authenticated read-only token", async () => {
|
|
const workflow = await fs.readFile(workflowPath, "utf8");
|
|
const preview = extractJob(workflow, "preview");
|
|
const build = extractStep(preview, "Build preview from pull request docs");
|
|
const validate = extractJob(workflow, "validate");
|
|
const testStep = extractStep(validate, "Test public docs validator");
|
|
|
|
assert.match(
|
|
preview,
|
|
/permissions:\n contents: read\n\n steps:/,
|
|
"preview job permissions must be limited to contents: read",
|
|
);
|
|
assert.match(build, new RegExp(`GITHUB_TOKEN: ${tokenExpression}`));
|
|
assert.doesNotMatch(
|
|
preview.replace(build, ""),
|
|
/GITHUB_TOKEN/,
|
|
"GITHUB_TOKEN must remain scoped to the landing build step",
|
|
);
|
|
assert.match(testStep, /scripts\/validate-public-docs\.test\.mjs/);
|
|
assert.match(testStep, /scripts\/notify-docs-workflow\.test\.mjs/);
|
|
assert.match(workflow, /- "scripts\/notify-docs-workflow\.test\.mjs"/);
|
|
});
|
|
|
|
test("preview comment publication is isolated from pull request content", async () => {
|
|
const workflow = await fs.readFile(workflowPath, "utf8");
|
|
const preview = extractJob(workflow, "preview");
|
|
const publication = extractJob(workflow, "publish-preview-link");
|
|
const publishStep = extractStep(publication, "Publish docs preview link");
|
|
|
|
assert.match(
|
|
preview,
|
|
/outputs:\n enabled: \$\{\{ steps\.cloudflare\.outputs\.enabled \}\}\n deployment_url: \$\{\{ steps\.deploy\.outputs\.deployment-url \}\}\n alias_url: \$\{\{ steps\.deploy\.outputs\.pages-deployment-alias-url \}\}/,
|
|
);
|
|
assert.match(publication, /needs: preview/);
|
|
assert.match(
|
|
publication,
|
|
/if: needs\.preview\.outputs\.enabled == 'true'/,
|
|
);
|
|
assert.match(publication, /permissions:\n contents: read\n issues: write\n pull-requests: write\n/);
|
|
assert.match(
|
|
publishStep,
|
|
new RegExp(
|
|
`DEPLOYMENT_URL: ${String.raw`\$\{\{ needs\.preview\.outputs\.deployment_url \}\}`}`,
|
|
),
|
|
);
|
|
assert.match(
|
|
publishStep,
|
|
new RegExp(
|
|
`ALIAS_URL: ${String.raw`\$\{\{ needs\.preview\.outputs\.alias_url \}\}`}`,
|
|
),
|
|
);
|
|
assert.match(publishStep, /uses: actions\/github-script@/);
|
|
assert.doesNotMatch(publication, /actions\/checkout@/);
|
|
assert.doesNotMatch(publication, /pnpm run build:pages/);
|
|
});
|