feat(prd-1): implement M2 - Forgejo token handling
- Add src/forgejo/token.ts: synchronous token handler that returns OVERRIDE_GITHUB_TOKEN or DEFAULT_WORKFLOW_TOKEN directly (no OIDC) - Wire platform-aware token setup into run.ts with early branch before existing setupGitHubToken() call - Add test/forgejo-token.test.ts with 8 test cases covering override precedence, default fallback, and error handling - GitHub token path remains completely unchanged Progress: 22% complete (M1, M2 done) - next: M3 (CI workflows) or M5 (comment URLs) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
72f11f320c
commit
385acacc32
4 files changed
+105
-2
No files matched your search
@@ -232,7 +232,7 @@ The upstream repo has 13 workflows in `.github/workflows/`. Strategy:
|
|||||||
- Files: `action.yml` (MODIFIED), `src/platform/detector.ts` (NEW)
|
- Files: `action.yml` (MODIFIED), `src/platform/detector.ts` (NEW)
|
||||||
- Success: `detectPlatform()` returns "forgejo" in Forgejo runner, "github" in GitHub runner. `action.yml` doesn't error on Forgejo.
|
- Success: `detectPlatform()` returns "forgejo" in Forgejo runner, "github" in GitHub runner. `action.yml` doesn't error on Forgejo.
|
||||||
|
|
||||||
- [ ] **M2: Forgejo token handling** — Create `src/forgejo/token.ts` that returns `GITHUB_TOKEN` / `FORGEJO_TOKEN` directly (no OIDC, no Anthropic exchange). Wire into `run.ts` with an early platform branch before the existing `setupGitHubToken()` call.
|
- [x] **M2: Forgejo token handling** — Create `src/forgejo/token.ts` that returns `GITHUB_TOKEN` / `FORGEJO_TOKEN` directly (no OIDC, no Anthropic exchange). Wire into `run.ts` with an early platform branch before the existing `setupGitHubToken()` call.
|
||||||
- Files: `src/forgejo/token.ts` (NEW), `src/entrypoints/run.ts` (MODIFIED — surgical addition at top of `run()`)
|
- Files: `src/forgejo/token.ts` (NEW), `src/entrypoints/run.ts` (MODIFIED — surgical addition at top of `run()`)
|
||||||
- Depends on: M1
|
- Depends on: M1
|
||||||
- Success: Token is available without OIDC on Forgejo. GitHub path unchanged.
|
- Success: Token is available without OIDC on Forgejo. GitHub path unchanged.
|
||||||
|
|||||||
+14
-1
@@ -12,6 +12,8 @@ import { spawn } from "child_process";
|
|||||||
import { appendFile } from "fs/promises";
|
import { appendFile } from "fs/promises";
|
||||||
import { existsSync, readFileSync } from "fs";
|
import { existsSync, readFileSync } from "fs";
|
||||||
import { setupGitHubToken, WorkflowValidationSkipError } from "../github/token";
|
import { setupGitHubToken, WorkflowValidationSkipError } from "../github/token";
|
||||||
|
import { setupForgejoToken } from "../forgejo/token";
|
||||||
|
import { detectPlatform } from "../platform/detector";
|
||||||
import { checkWritePermissions } from "../github/validation/permissions";
|
import { checkWritePermissions } from "../github/validation/permissions";
|
||||||
import { createOctokit } from "../github/api/client";
|
import { createOctokit } from "../github/api/client";
|
||||||
import type { Octokits } from "../github/api/client";
|
import type { Octokits } from "../github/api/client";
|
||||||
@@ -145,16 +147,27 @@ async function run() {
|
|||||||
`Auto-detected mode: ${modeName} for event: ${context.eventName}`,
|
`Auto-detected mode: ${modeName} for event: ${context.eventName}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Platform-aware token setup
|
||||||
|
const platform = detectPlatform();
|
||||||
|
console.log(`Platform detected: ${platform}`);
|
||||||
|
|
||||||
|
if (platform === "forgejo") {
|
||||||
|
githubToken = setupForgejoToken();
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
githubToken = await setupGitHubToken();
|
githubToken = await setupGitHubToken();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof WorkflowValidationSkipError) {
|
if (error instanceof WorkflowValidationSkipError) {
|
||||||
core.setOutput("skipped_due_to_workflow_validation_mismatch", "true");
|
core.setOutput(
|
||||||
|
"skipped_due_to_workflow_validation_mismatch",
|
||||||
|
"true",
|
||||||
|
);
|
||||||
console.log("Exiting due to workflow validation skip");
|
console.log("Exiting due to workflow validation skip");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
octokit = createOctokit(githubToken);
|
octokit = createOctokit(githubToken);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Forgejo token handling.
|
||||||
|
*
|
||||||
|
* Unlike GitHub (which uses OIDC → Anthropic exchange for an app token),
|
||||||
|
* Forgejo uses the runner's workflow token directly. No exchange needed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function setupForgejoToken(): string {
|
||||||
|
// 1. User-provided token (via github_token input → OVERRIDE_GITHUB_TOKEN)
|
||||||
|
const providedToken = process.env.OVERRIDE_GITHUB_TOKEN;
|
||||||
|
if (providedToken) {
|
||||||
|
console.log("Using provided token for Forgejo authentication");
|
||||||
|
return providedToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Runner's default workflow token (github.token → DEFAULT_WORKFLOW_TOKEN)
|
||||||
|
const defaultToken = process.env.DEFAULT_WORKFLOW_TOKEN;
|
||||||
|
if (defaultToken) {
|
||||||
|
console.log("Using default workflow token for Forgejo authentication");
|
||||||
|
return defaultToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
"No authentication token available for Forgejo. " +
|
||||||
|
"Provide a token via the 'github_token' input or ensure " +
|
||||||
|
"the workflow has a valid GITHUB_TOKEN.",
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { setupForgejoToken } from "../src/forgejo/token";
|
||||||
|
import { describe, it, expect, beforeEach } from "bun:test";
|
||||||
|
|
||||||
|
describe("setupForgejoToken", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
delete process.env.OVERRIDE_GITHUB_TOKEN;
|
||||||
|
delete process.env.DEFAULT_WORKFLOW_TOKEN;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("OVERRIDE_GITHUB_TOKEN (user-provided via github_token input)", () => {
|
||||||
|
it("should return OVERRIDE_GITHUB_TOKEN when set", () => {
|
||||||
|
process.env.OVERRIDE_GITHUB_TOKEN = "user-provided-token";
|
||||||
|
expect(setupForgejoToken()).toBe("user-provided-token");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should take precedence over DEFAULT_WORKFLOW_TOKEN", () => {
|
||||||
|
process.env.OVERRIDE_GITHUB_TOKEN = "override-token";
|
||||||
|
process.env.DEFAULT_WORKFLOW_TOKEN = "default-token";
|
||||||
|
expect(setupForgejoToken()).toBe("override-token");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not use empty OVERRIDE_GITHUB_TOKEN", () => {
|
||||||
|
process.env.OVERRIDE_GITHUB_TOKEN = "";
|
||||||
|
process.env.DEFAULT_WORKFLOW_TOKEN = "default-token";
|
||||||
|
expect(setupForgejoToken()).toBe("default-token");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("DEFAULT_WORKFLOW_TOKEN (runner's github.token)", () => {
|
||||||
|
it("should return DEFAULT_WORKFLOW_TOKEN when no override is set", () => {
|
||||||
|
process.env.DEFAULT_WORKFLOW_TOKEN = "workflow-token";
|
||||||
|
expect(setupForgejoToken()).toBe("workflow-token");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not use empty DEFAULT_WORKFLOW_TOKEN", () => {
|
||||||
|
process.env.DEFAULT_WORKFLOW_TOKEN = "";
|
||||||
|
expect(() => setupForgejoToken()).toThrow(
|
||||||
|
"No authentication token available for Forgejo",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("error handling", () => {
|
||||||
|
it("should throw when no token is available", () => {
|
||||||
|
expect(() => setupForgejoToken()).toThrow(
|
||||||
|
"No authentication token available for Forgejo",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw when both env vars are empty strings", () => {
|
||||||
|
process.env.OVERRIDE_GITHUB_TOKEN = "";
|
||||||
|
process.env.DEFAULT_WORKFLOW_TOKEN = "";
|
||||||
|
expect(() => setupForgejoToken()).toThrow(
|
||||||
|
"No authentication token available for Forgejo",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should include guidance in the error message", () => {
|
||||||
|
expect(() => setupForgejoToken()).toThrow("github_token");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user