Skip to content

feat(service): Add optional Warden backing service - #470

Merged
gricha merged 13 commits into
mainfrom
feat/warden-service
Aug 14, 2026
Merged

feat(service): Add optional Warden backing service#470
gricha merged 13 commits into
mainfrom
feat/warden-service

Conversation

@gricha

@gricha gricha commented Aug 13, 2026

Copy link
Copy Markdown
Member

Add an optional backing service for durable Warden run history, cost analysis, finding exploration, and repository-scoped memory.

The service is API-first and self-hostable. It provides a strict versioned ingestion contract, authenticated read APIs, service credentials, read-only personal tokens, and Junior-style Google OAuth for browser access. The reference app deploys to Vercel using Node functions, static dashboard assets, Marketplace Postgres, and Vercel Cron without Redis or an always-on worker.

Warden's CLI, GitHub Action, and SDK publish and recall through fail-open boundaries. A repository without a configured service behaves as it does today. Once a URL and token are configured, the client defaults to the findings profile with memory enabled while continuing to treat local JSONL, Action output, and SDK results as authoritative.

The change also includes replay, migrations, credential administration, retention and deletion boundaries, durable Postgres jobs, deployment documentation, and a compact API-backed dashboard. Passive memory candidates remain inactive by default; automatic promotion requires a separate explicit policy.

The auth scope, profile-redaction boundary, idempotent ingestion transaction, and serverless job leasing are the most important review surfaces.

Add a Vercel-ready Hono and Postgres service for run history,
cost analysis, findings, and repository memory.

Wire fail-open publishing and recall through CLI, Action, and SDK
entry points while preserving existing local outputs.

Include Google OAuth, read-only personal tokens, deployment docs, and a
compact API-backed dashboard.

Co-Authored-By: GPT-5.6 Codex <noreply@anthropic.com>
Comment thread pnpm-lock.yaml
Harden history filters, memory evidence selection, CLI operations, publishing, and run attribution. Validate cursors and projections earlier, preserve complete usage data, and keep the documented clean-checkout deployment flow executable.

Co-Authored-By: GPT-5.6 Codex <noreply@anthropic.com>
gricha and others added 2 commits August 13, 2026 16:24
Override Vercel's Python analysis helper to use minimatch 10.2.5, which fixes the high-severity ReDoS advisories reported by dependency review.

Co-Authored-By: GPT-5.6 Codex <noreply@anthropic.com>
Override path-to-regexp 6.1.0 with the compatible 6.3.0 release to address the high-severity backtracking advisory reported by dependency review.

Co-Authored-By: GPT-5.6 Codex <noreply@anthropic.com>
Pin the vulnerable Vercel path matcher and HTTP client versions to compatible patched releases. This removes the remaining high-severity advisories introduced by the service app's local Vercel tooling.

Co-Authored-By: GPT-5.6 Codex <noreply@anthropic.com>
Keep the Action publication test deterministic when GitHub Actions injects GITHUB_RUN_ATTEMPT. Rerun identity behavior remains covered separately.

Co-Authored-By: GPT-5.6 Codex <noreply@anthropic.com>
Comment thread packages/warden-service/src/administration/routes.ts
Comment thread packages/warden-service/src/dashboard-auth.ts
Comment thread packages/warden/src/action/workflow/pr-workflow.ts
Comment thread packages/warden-service/src/app.ts
Comment thread packages/warden/src/action/inputs.ts
Comment thread packages/warden/src/action/workflow/schedule.ts
Comment thread packages/warden/src/cli/args.ts
Comment thread packages/warden/src/cli/main.ts
Comment thread packages/warden/src/sdk/local.ts Outdated
Comment thread packages/warden/src/service/findings.ts
Comment thread packages/warden/src/service/projection.ts Outdated
Comment thread packages/warden/src/action/service.ts
Comment thread packages/warden/src/action/workflow/schedule.ts
Comment thread packages/warden/src/cli/main.ts
Comment thread packages/warden/src/cli/main.ts Outdated
Comment thread packages/warden/src/sdk/local.test.ts
Comment thread packages/warden/src/sdk/local.ts Outdated
Comment thread packages/warden/src/sdk/local.ts
Comment thread packages/warden/src/service/findings.ts
Comment thread packages/warden/src/service/options.ts
Comment thread packages/warden/src/service/options.ts
Comment thread packages/warden/src/service/projection.ts Outdated
Keep service failures from changing Warden results and retain valid run data at protocol limits.

Close tenant and token scope escalation paths.

Preserve memory context while publishing empty and failed executions consistently.

Co-Authored-By: GPT-5.6 Sol <noreply@anthropic.com>
Comment thread packages/warden-service/src/administration/routes.ts
Comment thread .github/workflows/ci.yml
Comment thread packages/warden/src/action/reporting/output.ts
Comment thread packages/warden/src/action/workflow/schedule.ts Outdated
Comment thread packages/warden/src/cli/args.ts
Comment thread packages/warden/src/cli/args.ts Outdated
Comment thread packages/warden/src/config/schema.ts
Comment thread packages/warden/src/sdk/local.ts
Comment thread packages/warden/src/service/options.ts Outdated
Comment thread packages/warden/src/service/projection.ts Outdated
Comment thread packages/warden/src/cli/main.ts
Comment thread packages/warden/src/action/reporting/output.ts
Comment thread packages/warden/src/cli/commands/service.ts Outdated
Comment thread packages/warden/src/service/findings.ts Outdated
Keep read exports within the history API data boundary and preserve
fail-open publication across early Action exits.

Resolve service defaults only after overrides, validate CLI inputs
strictly, and keep bounded projections internally consistent.

Co-Authored-By: GPT-5.6 Sol <noreply@anthropic.com>
Require HTTPS outside loopback and prevent environment tokens from using
repository-configured URLs.

Keep replay available when config parsing fails and normalize optional pull
request metadata at the service protocol boundary.

Co-Authored-By: GPT-5.6 Sol <noreply@anthropic.com>
Match the workspace-root output produced by filtered pnpm pack commands so the artifact upload finds both package tarballs.

Co-Authored-By: GPT-5.6 Sol <noreply@anthropic.com>
@gricha
gricha marked this pull request as ready for review August 13, 2026 19:30
Comment thread packages/warden-service/src/jobs/runner.ts
Comment thread packages/warden/src/action/workflow/pr-workflow.ts
Comment thread packages/warden/src/cli/commands/service.ts
Comment thread packages/warden/src/config/loader.ts
Comment thread packages/warden/src/service/findings.ts
Comment thread packages/warden/src/service/projection.ts
Comment thread packages/warden-service/src/administration/routes.ts
Comment thread packages/warden/src/cli/commands/service.test.ts
Comment thread packages/warden/src/service/projection.ts Outdated
Release unstarted jobs without consuming retries, preserve profile-aware config defaults and mixed usage attribution, and isolate replay tests from service environment variables.

Co-Authored-By: GPT-5.6 Sol <noreply@anthropic.com>
Bring the service PR up to date with offline policy and Pi runtime changes from main. Preserve both offline configuration and optional service resolution in the only overlapping CLI path.

Co-Authored-By: GPT-5.6 Sol <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a22c1cd. Configure here.

Comment thread .github/workflows/ci.yml
Comment thread packages/warden-service/src/runs/ingest.ts Outdated
Keep repository memory eligibility enabled after later runs opt out so queued extraction jobs retain access to their evidence.

Co-Authored-By: GPT-5.6 Sol <noreply@anthropic.com>
@gricha
gricha merged commit 6bf7ba9 into main Aug 14, 2026
18 checks passed
@gricha
gricha deleted the feat/warden-service branch August 14, 2026 06:52
Comment thread packages/warden/src/config/loader.ts
Comment on lines +31 to +43
const paths = context.pullRequest?.files.map((file) => file.filename) ?? [];
const response = await recallMemoryFailOpen(service, {
protocolVersion: 1,
clientRecallId: randomUUID(),
repository: {
provider: 'github',
owner: context.repository.owner,
name: context.repository.name,
fullName: context.repository.fullName,
},
skills: [...new Set(skills)],
languages: [...new Set(paths.map((path) => extname(path).slice(1)).filter(Boolean))],
paths,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

recallActionMemoryFailOpen silently drops repository memory when >500 files change

recallActionMemoryFailOpen sends the full changed-file list to the memory endpoint without truncating to the service's 500-item limit, so large pull requests silently forfeit recalled memories.

Evidence
  • MemoryRecallRequestSchema in the service API package defines paths: z.array(z.string().max(1_024)).max(500) (api.ts).
  • fetchPullRequestFiles in the event layer uses octokit.paginate and returns every changed file without truncation (event/context.ts).
  • recallActionMemoryFailOpen builds paths from context.pullRequest?.files.map(file => file.filename) and passes it directly to recallMemoryFailOpen (service.ts:31-43).
  • recallMemoryFailOpen delegates to createWardenServiceClient(...).recallMemory, which parses the request with MemoryRecallRequestSchema.parse; an oversized array throws a ZodError that is caught and returned as undefined (client.ts).
  • recallActionMemoryFailOpen then returns { memories: [] }, so the action proceeds without the expected historical context.

Identified by Warden · code-review · JXP-X2L

Comment on lines +93 to +134
location: {
...finding.location,
path: finding.location.path.slice(0, MAX_PATH_LENGTH),
},
} : {}),
...(finding.additionalLocations ? {
additionalLocations: finding.additionalLocations.slice(0, 20).map((location) => ({
...location,
path: location.path.slice(0, MAX_PATH_LENGTH),
})),
} : {}),
...(provenance ? { provenance } : {}),
...(sourceSnippet ? {
sourceEvidence: {
path: sourceSnippet.path.slice(0, MAX_PATH_LENGTH),
...(sourceSnippet.language ? { language: sourceSnippet.language } : {}),
startLine: sourceSnippet.startLine,
endLine: sourceSnippet.endLine,
targetStartLine: sourceSnippet.targetStartLine,
targetEndLine: sourceSnippet.targetEndLine,
content: sourceSnippet.lines.map((line) => line.content).join('\n').slice(0, 16_000),
},
} : {}),
};
}

export interface ServiceSkillReport {
executionId: string;
report: SkillReport;
triggerId?: string;
triggerName?: string;
skillDigest?: string;
findingProvenance?: Readonly<Record<string, FindingProvenance>>;
}

export interface BuildServiceRunProjectionInput {
service: Pick<ResolvedServiceOptions, 'data' | 'memory'>;
clientRunId: string;
source: 'cli' | 'action' | 'sdk' | 'replay';
wardenVersion: string;
startedAt: Date;
completedAt: Date;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty or whitespace-only finding fields silently break service envelope construction

findingRecord slices title, description, and path strings to max length but does not trim them or filter empty/whitespace-only values. Optional fields like verification and language also pass through whitespace-only strings because they are truthy in JavaScript. These values satisfy Warden's local FindingSchema but violate the service ShortTextSchema, DescriptionSchema, and PathSchema, which require z.string().trim().min(1). When buildServiceRunEnvelope later calls redactRunProjection, RunProjectionSchema.parse throws a ZodError; callers catch it and either skip service publication or, during CLI replay, emit the misleading error "Artifact is not a supported completed JSONL or findings-output file."

Evidence
  • FindingSchema.title is z.string() (no .min(1)) and validateFindings in sdk/extract.ts does not reject empty strings, so empty titles can reach findingRecord.
  • service/findings.ts:21-30 already uses boundedOptionalText to normalize PR metadata for the exact same service contract, showing the codebase already handles this pattern for service-facing data.
  • packages/warden-service-api/src/protocol.ts defines ShortTextSchema, DescriptionSchema, and PathSchema with .trim().min(1).
  • packages/warden-service-api/src/redaction.ts calls RunProjectionSchema.parse(), which throws when empty/whitespace-only strings appear in those fields.
  • In projection.ts lines 98-99, title and description are unconditionally included via .slice(0, MAX) with no empty-string guard, and optional fields at lines 101, 106, 110, 118-119 include whitespace-only strings because ...(value ? {...} : {}) treats ' ' as truthy.

Identified by Warden · code-review · ZCJ-85H

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant