Skip to content

Commit 0ac1092

Browse files
chitcommitclaude
andcommitted
fix: address PR review feedback across 10 files
- package.json: remove trailing space on kv:seed script line - ci.yml: add npm test step, fix secret allowlist to catch bracket notation (secrets['NAME']) in addition to dot notation - reusable-governance-gates.yml: same bracket notation fix - chittycompliance-dispatch.sh: replace string interpolation with jq -nc for all JSON payloads to prevent injection - org-governance-adversarial-review.sh: add defensive // [] for missingFiles and missingTriggers jq expressions - connect.ts: proper AuthVariables typing instead of @ts-expect-error - integrations.ts: normalize KV cache key with encodeURIComponent - wrangler.toml: default PLAID_ENV to sandbox, production override in [env.production.vars] - org-governance-pr-integration-loop.sh: add author verification against governance automation allowlist before auto-approve - .gitignore: exclude timestamped governance report artifacts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 01cdf57 commit 0ac1092

10 files changed

Lines changed: 44 additions & 28 deletions

.github/workflows/ci.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ jobs:
1414
shell: bash
1515
run: |
1616
set -euo pipefail
17-
secrets_in_use="$(grep -RhoE '\${{\s*secrets\.[A-Za-z_][A-Za-z0-9_]*\s*}}' .github/workflows \
18-
| sed -E 's/.*secrets\.([A-Za-z_][A-Za-z0-9_]*).*/\1/' \
17+
secrets_in_use="$(grep -RhoE '\$\{\{\s*secrets(\.[A-Za-z_][A-Za-z0-9_]*|\['"'"'\"[A-Za-z_][A-Za-z0-9_]*'"'"'\"\])\s*\}\}' .github/workflows \
18+
| sed -E "s/.*secrets[.\['\"]([A-Za-z_][A-Za-z0-9_]*).*/\1/" \
1919
| sort -u || true)"
2020
2121
if [[ -z "${secrets_in_use}" ]]; then
@@ -76,6 +76,8 @@ jobs:
7676
run: npm audit --audit-level=high
7777
- name: Typecheck
7878
run: npx tsc -p tsconfig.json --noEmit
79+
- name: Test
80+
run: npm test
7981
- name: Governance Pressure Tests
8082
run: bash scripts/pressure-test-governance.sh
8183
- name: Lint (skipped)

.github/workflows/reusable-governance-gates.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ jobs:
2020
shell: bash
2121
run: |
2222
set -euo pipefail
23-
secrets_in_use="$(grep -RhoE '\$\{\{\s*secrets\.[A-Za-z_][A-Za-z0-9_]*\s*\}\}' .github/workflows \
24-
| sed -E 's/.*secrets\.([A-Za-z_][A-Za-z0-9_]*).*/\1/' \
23+
secrets_in_use="$(grep -RhoE '\$\{\{\s*secrets(\.[A-Za-z_][A-Za-z0-9_]*|\['"'"'\"[A-Za-z_][A-Za-z0-9_]*'"'"'\"\])\s*\}\}' .github/workflows \
24+
| sed -E "s/.*secrets[.\['\"]([A-Za-z_][A-Za-z0-9_]*).*/\1/" \
2525
| sort -u || true)"
2626
2727
if [[ -z "${secrets_in_use}" ]]; then

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ ui/dist/
1515
# External service repos (cloned for reference, not tracked)
1616
_ext/
1717

18+
# Generated governance reports (timestamped artifacts)
19+
reports/org-governance-*/report-*.json
20+
reports/org-governance-*/report-*.jsonl
21+
reports/org-governance-*/report-*.md
22+
1823
# Build infos and OS cruft
1924
ui/tsconfig.tsbuildinfo
2025
.DS_Store

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"predeploy": "npm run typecheck",
1414
"db:generate": "drizzle-kit generate",
1515
"db:migrate": "drizzle-kit migrate",
16-
"kv:seed": "bash scripts/seed-kv.sh ${KV_NAMESPACE_ID:-}" ,
16+
"kv:seed": "bash scripts/seed-kv.sh ${KV_NAMESPACE_ID:-}",
1717
"ui:dev": "cd ui && vite dev",
1818
"ui:build": "cd ui && vite build",
1919
"ui:preview": "cd ui && vite preview",

scripts/chittycompliance-dispatch.sh

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,14 @@ if [[ -n "${BROKER_URL}" && -n "${BROKER_TOKEN}" ]]; then
7777
broker_response="$(run_with_timeout curl -fsS -X POST "${BROKER_URL}" \
7878
-H "Authorization: Bearer ${BROKER_TOKEN}" \
7979
-H "Content-Type: application/json" \
80-
-d "{
81-
\"repo\":\"${REPO}\",
82-
\"mode\":\"${MODE}\",
83-
\"findings\":\"${FINDINGS}\",
84-
\"context\":{
85-
\"source\":\"org-governance-control-loop\",
86-
\"run_id\":\"${GITHUB_RUN_ID:-local}\",
87-
\"actor\":\"${GITHUB_ACTOR:-local}\",
88-
\"workflow\":\"${GITHUB_WORKFLOW:-local}\"
89-
},
90-
\"requested_access\":[\"gateway_dispatch\",\"agent_orchestrator\"]
91-
}" 2>/dev/null || true)"
80+
-d "$(jq -nc \
81+
--arg repo "${REPO}" \
82+
--arg mode "${MODE}" \
83+
--arg findings "${FINDINGS}" \
84+
--arg run_id "${GITHUB_RUN_ID:-local}" \
85+
--arg actor "${GITHUB_ACTOR:-local}" \
86+
--arg workflow "${GITHUB_WORKFLOW:-local}" \
87+
'{repo:$repo, mode:$mode, findings:$findings, context:{source:"org-governance-control-loop", run_id:$run_id, actor:$actor, workflow:$workflow}, requested_access:["gateway_dispatch","agent_orchestrator"]}')" 2>/dev/null || true)"
9288

9389
if [[ -n "${broker_response}" ]]; then
9490
decision="$(jq -r '.decision // "deny"' <<< "${broker_response}" 2>/dev/null || echo "deny")"
@@ -137,7 +133,7 @@ fi
137133
if [[ -n "${CHITTYCOMPLIANCE_AGENT_ENDPOINT:-}" ]]; then
138134
run_with_timeout curl -fsS -X POST "${CHITTYCOMPLIANCE_AGENT_ENDPOINT}" \
139135
-H "Content-Type: application/json" \
140-
-d "{\"repo\":\"${REPO}\",\"mode\":\"${MODE}\",\"findings\":\"${FINDINGS}\"}" >/dev/null && dispatch_success=1 || true
136+
-d "$(jq -nc --arg repo "${REPO}" --arg mode "${MODE}" --arg findings "${FINDINGS}" '{repo:$repo, mode:$mode, findings:$findings}')" >/dev/null && dispatch_success=1 || true
141137
fi
142138

143139
# Primary path: ChittyGateway / ChittyAgent orchestrator on Cloudflare Workers AI.
@@ -149,7 +145,7 @@ if [[ -n "${gateway_url}" ]]; then
149145
run_with_timeout curl -fsS -X POST "${gateway_url}" \
150146
-H "Content-Type: application/json" \
151147
"${auth_headers[@]}" \
152-
-d "{\"pipeline\":\"chittycompliance\",\"repo\":\"${REPO}\",\"mode\":\"${MODE}\",\"findings\":\"${FINDINGS}\"}" >/dev/null && dispatch_success=1 || true
148+
-d "$(jq -nc --arg repo "${REPO}" --arg mode "${MODE}" --arg findings "${FINDINGS}" '{pipeline:"chittycompliance", repo:$repo, mode:$mode, findings:$findings}')" >/dev/null && dispatch_success=1 || true
153149
fi
154150

155151
if [[ -n "${orchestrator_url}" ]]; then
@@ -160,7 +156,7 @@ if [[ -n "${orchestrator_url}" ]]; then
160156
run_with_timeout curl -fsS -X POST "${orchestrator_url}" \
161157
-H "Content-Type: application/json" \
162158
"${auth_headers[@]}" \
163-
-d "{\"operation\":\"governance_review\",\"repo\":\"${REPO}\",\"mode\":\"${MODE}\",\"findings\":\"${FINDINGS}\"}" >/dev/null && dispatch_success=1 || true
159+
-d "$(jq -nc --arg repo "${REPO}" --arg mode "${MODE}" --arg findings "${FINDINGS}" '{operation:"governance_review", repo:$repo, mode:$mode, findings:$findings}')" >/dev/null && dispatch_success=1 || true
164160
fi
165161

166162
if [[ "${STRICT_MODE}" == "true" && "${dispatch_success}" -eq 0 ]]; then

scripts/org-governance-adversarial-review.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ while IFS= read -r row; do
6363
[[ -z "${row}" ]] && continue
6464
full_repo="$(jq -r '.fullRepo' <<< "${row}")"
6565
score="$(jq -r '.score' <<< "${row}")"
66-
missing_files="$(jq -r '.missingFiles | join(", ")' <<< "${row}")"
67-
missing_patterns="$(jq -r '.missingPatterns // [] | join(", ")' <<< "${row}")"
68-
missing_triggers="$(jq -r '.missingTriggers | join(", ")' <<< "${row}")"
66+
missing_files="$(jq -r '(.missingFiles // []) | join(", ")' <<< "${row}")"
67+
missing_patterns="$(jq -r '(.missingPatterns // []) | join(", ")' <<< "${row}")"
68+
missing_triggers="$(jq -r '(.missingTriggers // []) | join(", ")' <<< "${row}")"
6969
missing_status_checks="$(jq -r '.missingStatusChecks // [] | join(", ")' <<< "${row}")"
7070
missing_repo_settings="$(jq -r '.missingRepoSettings // [] | join(", ")' <<< "${row}")"
7171

scripts/org-governance-pr-integration-loop.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,15 @@ while IFS= read -r full_repo; do
116116
auto_merge_enabled="$(jq -r 'if .autoMergeRequest == null then "false" else "true" end' <<< "${pr}")"
117117
pr_author="$(jq -r '.author.login // ""' <<< "${pr}")"
118118

119+
# Only process PRs created by known governance automation accounts
120+
allowed_authors="chitcommit github-actions[bot] dependabot[bot]"
121+
if ! echo "${allowed_authors}" | grep -qw "${pr_author}"; then
122+
blocked=$((blocked + 1))
123+
echo "Blocked ${pr_url}: author '${pr_author}' not in governance automation allowlist"
124+
queue_event "${full_repo}" "${pr_number}" "${pr_url}" "integration" "blocked" "untrusted_author:${pr_author}"
125+
continue
126+
fi
127+
119128
if [[ "${is_draft}" == "true" ]]; then
120129
blocked=$((blocked + 1))
121130
echo "Blocked ${pr_url}: draft"

src/lib/integrations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ export function connectClient(env: Env) {
315315
return {
316316
/** Discover a service URL by name */
317317
discover: async (serviceName: string): Promise<string | null> => {
318-
const key = `connect:discover:${serviceName}`;
318+
const key = `connect:discover:${encodeURIComponent(serviceName)}`;
319319
// KV cache (5 minutes)
320320
try {
321321
const cached = await env.COMMAND_KV.get(key);

src/routes/connect.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { Hono } from 'hono';
22
import type { Env } from '../index';
3+
import type { AuthVariables } from '../middleware/auth';
34
import { connectClient } from '../lib/integrations';
45

5-
export const connectRoutes = new Hono<{ Bindings: Env }>();
6+
export const connectRoutes = new Hono<{ Bindings: Env; Variables: AuthVariables }>();
67

78
connectRoutes.get('/connect/status', async (c) => {
89
const url = c.env.CHITTYCONNECT_URL;
@@ -23,8 +24,7 @@ connectRoutes.post('/connect/discover', async (c) => {
2324
// Simple per-minute rate limit (KV-configurable). Subject: userId or token hash.
2425
const authHeader = c.req.header('Authorization') || '';
2526
const token = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : '';
26-
// @ts-expect-error app-level variables
27-
const userId = (c.get('userId') as string | undefined) || 'anonymous';
27+
const userId = c.get('userId') || 'anonymous';
2828
const subject = userId === 'bridge-service' ? 'svc:bridge-service' : `usr:${userId}`;
2929
const rateRaw = await c.env.COMMAND_KV.get('discover:rate_limit');
3030
const limit = rateRaw ? Math.max(1, parseInt(rateRaw)) : 60; // default 60/min

wrangler.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ CHITTYLEDGER_URL = "https://ledger.chitty.cc"
1414
CHITTYFINANCE_URL = "https://finance.chitty.cc"
1515
CHITTYCHARGE_URL = "https://charge.chitty.cc"
1616
CHITTYCONNECT_URL = "https://connect.chitty.cc"
17-
PLAID_ENV = "production"
17+
PLAID_ENV = "sandbox"
1818
CHITTYBOOKS_URL = "https://chittybooks.chitty.cc"
1919
CHITTYASSETS_URL = "https://chittyassets.chitty.cc"
2020
CHITTYSCRAPE_URL = "https://scrape.chitty.cc"
@@ -58,3 +58,7 @@ crons = [
5858
"0 14 * * 1", # Weekly Monday 8 AM CT: Utility scrapers
5959
"0 15 1 * *" # Monthly 1st 9 AM CT: Mortgage, property tax
6060
]
61+
62+
# Production overrides
63+
[env.production.vars]
64+
PLAID_ENV = "production"

0 commit comments

Comments
 (0)