From ac58521d95712a2b2475fffa2e9c6d5037434102 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Sun, 12 Jul 2026 02:09:50 -0700 Subject: [PATCH 1/3] docs(selfhost): document the claude code token secret file + fix stale screenshots note Two drift fixes found while auditing the recent secrets-migration and screenshot-allowlist changes: - The security and AI-providers docs pages only described the inline .env path for CLAUDE_CODE_OAUTH_TOKEN; add the secrets/*.txt file alternative now that docker-compose.yml supports it. - config/examples/gittensory.full.yml and .gittensory.yml.example both still called `screenshots` a "plain symmetric override" -- #4990 made it allowlist-required (force-off only outside the rollout allowlist), the same asymmetry as safety/grounding. Update both mirrored comment blocks to match. --- .gittensory.yml.example | 18 +++++++++++------- .../routes/docs.self-hosting-ai-providers.tsx | 9 ++++++++- .../src/routes/docs.self-hosting-security.tsx | 12 ++++++------ config/examples/gittensory.full.yml | 18 +++++++++++------- 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/.gittensory.yml.example b/.gittensory.yml.example index 7047f10e57..f4257cb726 100644 --- a/.gittensory.yml.example +++ b/.gittensory.yml.example @@ -1106,13 +1106,17 @@ settings: # an operator who sets nothing keeps today's behavior). Exception: `safety` is force-on-only -- an untrusted # repo-controlled `false` is treated as "no opinion" rather than an active force-off (#2269), since a # lower-trust actor must never be able to silently defeat the operator's own security-hardening enablement. -# `e2eTests` (#4190), `screenshots` (#4616), and `improvementSignal` (#4738, foundation phase of the #4737 -# PR-improvement-signal epic) are plain symmetric overrides like rag/reputation/unifiedComment -- none carries -# a security-hardening or full-file-fetch rationale (unlike safety/grounding) that would justify a force-on/ -# force-off asymmetry. `screenshots` sits UNDER the separate, richer `review.visual.*` block further below -# (route/preview-URL config, and `review.visual.enabled: false` as an always-available additional force-off); -# this key only answers "does capture run for this repo at all," the same question its siblings answer for -# their own feature. `improvementSignal` is activation wiring only for now -- no tier reads the resolved +# `screenshots` (#4616) is ALSO asymmetric as of #4990: allowlisted is now a hard requirement for force-ON, +# the same as safety/grounding -- real Browserless rendering cost and a publicly-rendered PR image mean a +# lower-trust repo must not be able to self-activate capture just by setting this to `true` in its own +# config; a repo-level `false` can still force it OFF within an allowlisted repo. `screenshots` sits UNDER +# the separate, richer `review.visual.*` block further below (route/preview-URL config, and +# `review.visual.enabled: false` as an always-available additional force-off); this key only answers "does +# capture run for this repo at all," the same question its siblings answer for their own feature. +# `e2eTests` (#4190) and `improvementSignal` (#4738, foundation phase of the #4737 PR-improvement-signal +# epic) remain plain symmetric overrides like rag/reputation/unifiedComment -- neither carries a +# security-hardening or full-file-fetch rationale that would justify a force-on/force-off asymmetry. +# `improvementSignal` is activation wiring only for now -- no tier reads the resolved # value yet. # features: # rag: true diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-ai-providers.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-ai-providers.tsx index 8711602164..80ffb75527 100644 --- a/apps/gittensory-ui/src/routes/docs.self-hosting-ai-providers.tsx +++ b/apps/gittensory-ui/src/routes/docs.self-hosting-ai-providers.tsx @@ -186,6 +186,13 @@ CLAUDE_AI_EFFORT=medium`} instead:
+ Prefer not pasting the raw token into .env? Write it into{" "}
+ secrets/claude_code_oauth_token.txt instead (see{" "}
+ Security's secret-file section) and leave{" "}
+ CLAUDE_CODE_OAUTH_TOKEN unset in .env — the same recreate step
+ above picks it up either way.
+
@@ -216,7 +223,7 @@ CLAUDE_AI_EFFORT=medium`}
{
title: "claude_code_no_oauth_token",
description:
- "CLAUDE_CODE_OAUTH_TOKEN is unset. Add it to .env and recreate the service.",
+ "CLAUDE_CODE_OAUTH_TOKEN is unset and no secrets/claude_code_oauth_token.txt file is populated. Set either and recreate the service.",
},
{
title: "claude_code_error_401",
diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-security.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-security.tsx
index 83aeb69a4a..0a766f1b36 100644
--- a/apps/gittensory-ui/src/routes/docs.self-hosting-security.tsx
+++ b/apps/gittensory-ui/src/routes/docs.self-hosting-security.tsx
@@ -56,12 +56,12 @@ function SelfHostingSecurity() {
docker-compose.yml ships native Docker Compose secrets: mounts for
the highest-value secrets (the GitHub App private key, webhook secret, API/MCP/internal-job
tokens, the setup token, the two token-encryption master keys, the Orb enrollment secret,
- and the PagerDuty routing key) — file-mounted at /run/secrets/<name>,
- never exposed via docker inspect or docker compose config the way
- a plain environment:/env_file value is. This is purely additive:
- an inline .env value always takes priority if you set both, so you can migrate
- one secret at a time, or not at all. See secrets/README.md for the full file
- list.
+ the PagerDuty routing key, and the Claude Code subscription token) — file-mounted at{" "}
+ /run/secrets/<name>, never exposed via docker inspect or{" "}
+ docker compose config the way a plain environment:/
+ env_file value is. This is purely additive: an inline .env value
+ always takes priority if you set both, so you can migrate one secret at a time, or not at
+ all. See secrets/README.md for the full file list.