mirror of
https://github.com/hanzoai/agent.git
synced 2026-09-11 21:08:51 +00:00
P0-1: internal/server/middleware/auth.go + grpc_auth.go — APIKeyAuth no longer runs in series after RequireIdentity. The API key is the trust boundary when apiAuth.enabled=true: identity headers become informational, the key's bound org_id (loaded at validation) is authoritative. Rejects 403 on X-Org-Id mismatch with key-bound org. No more X-API-Key + attacker-chosen X-Org-Id = cross-tenant access. P0-2: APIKeyAuth uses crypto/subtle.ConstantTimeCompare. Closes timing leak on bearer-token compare. P0-3: migrations/020_backfill_org_id.sql + 021_org_id_not_null.sql sequence + scripts/audit-org-id.sh + MIGRATION_ORDER.md document the deploy order: 019 add column → audit → 020 backfill from created_by/users.org_id → verify zero empty rows → 021 NOT NULL + CHECK constraint → flip AGENTD_REQUIRE_IDENTITY=true. Hard prereq before any production migration. CC: deployments/helm/hanzo-agents/templates/networkpolicy.yaml allows ingress only from podSelector matchLabels app=hanzoai-gateway. Empty X-Org-Id rejected at middleware in cloud mode (defense-in-depth). Tests: pkg/auth + internal/server/middleware both PASS. Closes Red 2026-04-27 agent findings.
71 lines
3.5 KiB
SQL
71 lines
3.5 KiB
SQL
-- 020_backfill_org_id.sql
|
|
--
|
|
-- Backfill org_id for rows created BEFORE migration 019 set the
|
|
-- column. Those rows currently carry org_id = '' (the 019 DEFAULT).
|
|
-- This migration assigns them to the reserved sentinel org
|
|
-- `_legacy`, which:
|
|
--
|
|
-- * Is NOT a valid IAM org slug (leading underscore is reserved
|
|
-- in IAM owner-claim spec, see ~/work/hanzo/CLAUDE.md
|
|
-- 2026-03-27 HTTP-header convention).
|
|
-- * Cannot be set by any caller — RequireIdentity rejects empty,
|
|
-- and the gateway maps real owner claims (no leading '_').
|
|
-- * Lets the SQL layer enforce non-empty org_id (migration 021's
|
|
-- CHECK constraint) without losing legacy data.
|
|
--
|
|
-- Per-table mapping decision:
|
|
--
|
|
-- executions, workflow_runs, workflow_steps, workflow_*_events,
|
|
-- execution_webhook_events, observability_*:
|
|
-- No reliable created_by/owner column exists on these tables.
|
|
-- Legacy rows are operator-shared until explicit migration via
|
|
-- `agentctl migrate-legacy --to <org>`.
|
|
--
|
|
-- did_registry, agent_dids, component_dids, execution_vcs,
|
|
-- workflow_vcs:
|
|
-- Same — no owner column. The DID/VC graph predates multitenant.
|
|
-- Operators must re-anchor these via the DID service after
|
|
-- assigning a real org.
|
|
--
|
|
-- This migration is IDEMPOTENT and SAFE to re-run: it only touches
|
|
-- rows where org_id = '' (the 019 default sentinel).
|
|
|
|
-- +goose Up
|
|
-- +goose StatementBegin
|
|
|
|
UPDATE executions SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE workflow_runs SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE workflow_steps SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE did_registry SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE agent_dids SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE component_dids SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE execution_vcs SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE workflow_vcs SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE execution_webhook_events SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE workflow_execution_events SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE workflow_run_events SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE observability_webhooks SET org_id = '_legacy' WHERE org_id = '';
|
|
UPDATE observability_dead_letter_queue SET org_id = '_legacy' WHERE org_id = '';
|
|
|
|
-- +goose StatementEnd
|
|
|
|
-- +goose Down
|
|
-- +goose StatementBegin
|
|
|
|
-- Reverse only the sentinel assignment. Real org_id values stay.
|
|
UPDATE observability_dead_letter_queue SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE observability_webhooks SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE workflow_run_events SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE workflow_execution_events SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE execution_webhook_events SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE workflow_vcs SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE execution_vcs SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE component_dids SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE agent_dids SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE did_registry SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE workflow_steps SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE workflow_runs SET org_id = '' WHERE org_id = '_legacy';
|
|
UPDATE executions SET org_id = '' WHERE org_id = '_legacy';
|
|
|
|
-- +goose StatementEnd
|