Accept lowercase profile types and anchor sides when reading
This commit is contained in:
+6
-1
@@ -28,6 +28,11 @@ const VERDICTS = new Map<string, [event: string, mark: string]>([
|
|||||||
]);
|
]);
|
||||||
const PROFILE_TYPES = new Set<unknown>(["CLAUDE", "CODEX", "OPENCODE"]);
|
const PROFILE_TYPES = new Set<unknown>(["CLAUDE", "CODEX", "OPENCODE"]);
|
||||||
const FAILURE_REASONS = new Set<unknown>(["SIGN_IN_FAILED", "USAGE_EXHAUSTED", "FAILED"]);
|
const FAILURE_REASONS = new Set<unknown>(["SIGN_IN_FAILED", "USAGE_EXHAUSTED", "FAILED"]);
|
||||||
|
// Anchors written before the UPPER_SNAKE switch spell sides in lowercase.
|
||||||
|
const OLD_SIDES = new Map<unknown, Anchor["side"]>([
|
||||||
|
["new", "NEW"],
|
||||||
|
["old", "OLD"],
|
||||||
|
]);
|
||||||
const isProfileType = (value: unknown): value is ProfileFailure["type"] => PROFILE_TYPES.has(value);
|
const isProfileType = (value: unknown): value is ProfileFailure["type"] => PROFILE_TYPES.has(value);
|
||||||
const isFailureReason = (value: unknown): value is FailureReason => FAILURE_REASONS.has(value);
|
const isFailureReason = (value: unknown): value is FailureReason => FAILURE_REASONS.has(value);
|
||||||
const failureComment = (failures: ProfileFailure[]): string =>
|
const failureComment = (failures: ProfileFailure[]): string =>
|
||||||
@@ -56,7 +61,7 @@ function parseAnchors(text: string, sourcePath: string): Anchor[] {
|
|||||||
const path = field(entry, "path");
|
const path = field(entry, "path");
|
||||||
const line = field(entry, "line");
|
const line = field(entry, "line");
|
||||||
const givenSide = field(entry, "side");
|
const givenSide = field(entry, "side");
|
||||||
const side = givenSide === undefined ? "NEW" : givenSide;
|
const side = givenSide === undefined ? "NEW" : (OLD_SIDES.get(givenSide) ?? givenSide);
|
||||||
const body = field(entry, "body");
|
const body = field(entry, "body");
|
||||||
if (typeof path !== "string" || path === "") {
|
if (typeof path !== "string" || path === "") {
|
||||||
throw new TypeError(`${at}.path: expected a repository path`);
|
throw new TypeError(`${at}.path: expected a repository path`);
|
||||||
|
|||||||
@@ -65,3 +65,14 @@ test("rejects malformed central credentials", async () => {
|
|||||||
),
|
),
|
||||||
).rejects.toThrow("profiles[0].token");
|
).rejects.toThrow("profiles[0].token");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("reads lowercase profile types from older credentials", async () => {
|
||||||
|
const credentials = await parseCredentials(
|
||||||
|
JSON.stringify({
|
||||||
|
"reviewer-token": ENCRYPTED,
|
||||||
|
profiles: [{ type: "codex" }, { type: "claude", token: ENCRYPTED }],
|
||||||
|
}),
|
||||||
|
MASTER_KEY,
|
||||||
|
);
|
||||||
|
expect(credentials.profiles.map(({ type }) => type)).toStrictEqual(["CODEX", "CLAUDE"]);
|
||||||
|
});
|
||||||
|
|||||||
@@ -78,6 +78,17 @@ export async function encryptCredential(
|
|||||||
return `v1:${encodeBase64Url(nonce)}:${encodeBase64Url(new Uint8Array(ciphertext))}`;
|
return `v1:${encodeBase64Url(nonce)}:${encodeBase64Url(new Uint8Array(ciphertext))}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// profiles.json files written before the UPPER_SNAKE switch spell types in lowercase.
|
||||||
|
const OLD_PROFILE_TYPES = new Map<unknown, BotProfile["type"]>([
|
||||||
|
["claude", "CLAUDE"],
|
||||||
|
["codex", "CODEX"],
|
||||||
|
["opencode", "OPENCODE"],
|
||||||
|
]);
|
||||||
|
|
||||||
|
function currentSpelling(type: unknown): unknown {
|
||||||
|
return OLD_PROFILE_TYPES.get(type) ?? type;
|
||||||
|
}
|
||||||
|
|
||||||
async function parseProfile(entry: unknown, index: number, masterKey: string): Promise<BotProfile> {
|
async function parseProfile(entry: unknown, index: number, masterKey: string): Promise<BotProfile> {
|
||||||
const at = `profiles[${index}]`;
|
const at = `profiles[${index}]`;
|
||||||
if (!isMapping(entry)) {
|
if (!isMapping(entry)) {
|
||||||
@@ -88,7 +99,7 @@ async function parseProfile(entry: unknown, index: number, masterKey: string): P
|
|||||||
throw new Error(`${at}.${key}: unknown field`);
|
throw new Error(`${at}.${key}: unknown field`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const type = field(entry, "type");
|
const type = currentSpelling(field(entry, "type"));
|
||||||
const model = field(entry, "model");
|
const model = field(entry, "model");
|
||||||
const token = field(entry, "token");
|
const token = field(entry, "token");
|
||||||
if (type !== "CLAUDE" && type !== "CODEX" && type !== "OPENCODE") {
|
if (type !== "CLAUDE" && type !== "CODEX" && type !== "OPENCODE") {
|
||||||
|
|||||||
Reference in New Issue
Block a user