Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/web/e2e/mock-server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,10 @@ function handleApiGet(pathname, fleet = FLEET) {
// The REAL chat.compact flag (runtime/flags.py) — enabled so commands.spec sees
// /compact in the slash menu; the flag-off path is covered via ?flag:chat.compact=off.
{ id: "chat.compact", description: "/compact — summarize + archive a chat thread.", tier: "dev", owner: "kj", remove_by: "2026-09-01", enabled: true, source: "channel" },
// The REAL secrets-panel flag (runtime/flags.py) — tier "dev", so it resolves ON in
// this channel "dev" mock. Settings ▸ Secrets is visible in e2e exactly as on dev;
// its flag-off (prod) path is covered by the source-level secretsGate.test unit test.
{ id: "secrets-panel", description: "Settings ▸ Secrets — external secrets manager panel.", tier: "dev", owner: "kj", remove_by: "2026-10-01", enabled: true, source: "channel" },
],
};
default:
Expand Down
5 changes: 4 additions & 1 deletion apps/web/src/settings/SettingsSurface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ const AGENT_SECTIONS: Section[] = [
{ id: "behavior", label: "Behavior", icon: Brain, render: () => <SettingsCategoryPanel category="Behavior" title="Behavior" /> },
{ id: "knowledge", label: "Knowledge", icon: Database, render: () => <SettingsCategoryPanel category="Knowledge" title="Knowledge" /> },
// External secrets manager (ADR 0080) — schema fields + the status/test/sync card.
{ id: "secrets", label: "Secrets", icon: Lock, render: () => <SecretsPanel /> },
// Behind `secrets-panel` (ADR 0068), dev channel only — see the flag in runtime/flags.py.
// Flag-off: `shown()` drops it from the nav AND from id resolution, so a persisted "secrets"
// id falls back to the first visible section instead of a blank pane.
{ id: "secrets", label: "Secrets", icon: Lock, flag: "secrets-panel", render: () => <SecretsPanel /> },
Comment thread
mabry1985 marked this conversation as resolved.
{ id: "plugins", label: "Plugins", icon: Puzzle, render: () => <PluginSettingsHome /> },
];

Expand Down
26 changes: 26 additions & 0 deletions apps/web/src/settings/secretsGate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { describe, expect, it } from "vitest";
import src from "./SettingsSurface.tsx?raw";
import flags from "../../../../runtime/flags.py?raw";

// Settings ▸ Secrets is gated to the dev channel (ADR 0068). The external secrets manager's
// connect/test/sync flow stays behind `secrets-panel` until it's exercised end to end, so it
// only shows on the dev channel / via override (#2120).
//
// Source-level because the failure mode is someone deleting the `flag:` key during an
// unrelated edit: that type-checks, renders fine on their machine, and silently re-exposes a
// pre-release panel on the prod channel.
describe("Settings ▸ Secrets is flag-gated", () => {
it("the section declares the flag", () => {
expect(src).toMatch(/id: "secrets"[^}]*flag: "secrets-panel"/);
});

it("flag-off sections are filtered from nav AND from id resolution", () => {
// Filtering only the nav would leave a persisted "secrets" id rendering the panel.
expect(src).toContain("const shown = (list: Section[])");
expect(src).toMatch(/const sections = \[\s*\.\.\.agentSections/);
});
Comment thread
mabry1985 marked this conversation as resolved.
Outdated

it("the flag ships at tier dev", () => {
expect(flags).toMatch(/id="secrets-panel"[\s\S]*?tier="dev"/);
});
});
11 changes: 11 additions & 0 deletions runtime/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ class Flag:
owner="kj",
remove_by="2026-10-01",
),
Flag(
id="secrets-panel",
description=(
"Settings ▸ Secrets — external secrets manager panel (ADR 0080). Dev channel "
"only while the connect/test/sync flow stabilizes; graduate to `on` once it's "
"exercised end to end (#2120)."
),
tier="dev",
owner="kj",
remove_by="2026-10-01",
),
]


Expand Down
Loading