@bongos/core 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongos-core.json +5727 -0
- package/.claude/skills/blocker-review/SKILL.md +91 -0
- package/.claude/skills/blocker-solve/SKILL.md +96 -0
- package/.claude/skills/builder-backup/SKILL.md +54 -0
- package/.claude/skills/builder-box/SKILL.md +45 -0
- package/.claude/skills/builder-claim/SKILL.md +76 -0
- package/.claude/skills/builder-connect/SKILL.md +59 -0
- package/.claude/skills/builder-cost/SKILL.md +47 -0
- package/.claude/skills/builder-end/SKILL.md +81 -0
- package/.claude/skills/builder-exit/SKILL.md +88 -0
- package/.claude/skills/builder-key/SKILL.md +40 -0
- package/.claude/skills/builder-reauth/SKILL.md +50 -0
- package/.claude/skills/builder-redteam/SKILL.md +109 -0
- package/.claude/skills/builder-release/SKILL.md +41 -0
- package/.claude/skills/builder-setup/SKILL.md +62 -0
- package/.claude/skills/builder-ship/SKILL.md +79 -0
- package/.claude/skills/builder-stage/SKILL.md +51 -0
- package/.claude/skills/builder-start/SKILL.md +46 -0
- package/.claude/skills/close-box/SKILL.md +43 -0
- package/.claude/skills/design-sync/SKILL.md +69 -0
- package/.claude/skills/dev/SKILL.md +49 -0
- package/.claude/skills/feedback/SKILL.md +32 -0
- package/.claude/skills/figma-design-sync/SKILL.md +74 -0
- package/.claude/skills/goal-review/SKILL.md +89 -0
- package/.claude/skills/idea-triage/SKILL.md +144 -0
- package/.claude/skills/ideate/SKILL.md +82 -0
- package/.claude/skills/merge-mode/SKILL.md +169 -0
- package/.claude/skills/new-project/SKILL.md +108 -0
- package/.claude/skills/otb-character-review/SKILL.md +71 -0
- package/.claude/skills/otb-design-review/SKILL.md +47 -0
- package/.claude/skills/otb-feedback-capture/SKILL.md +45 -0
- package/.claude/skills/otb-figma-sync/SKILL.md +54 -0
- package/.claude/skills/otb-tile-generate/SKILL.md +45 -0
- package/.claude/skills/paint/SKILL.md +70 -0
- package/.claude/skills/planning-session/SKILL.md +299 -0
- package/.claude/skills/priority-session/SKILL.md +134 -0
- package/.claude/skills/read-session-export/SKILL.md +58 -0
- package/.claude/skills/recall/SKILL.md +52 -0
- package/.claude/skills/session-handoff/SKILL.md +46 -0
- package/.claude/skills/status/SKILL.md +33 -0
- package/.devcontainer/Dockerfile +69 -0
- package/.devcontainer/README.md +73 -0
- package/.devcontainer/devcontainer-lock.json +19 -0
- package/.devcontainer/devcontainer.json +93 -0
- package/.devcontainer/healthcheck.sh +84 -0
- package/.devcontainer/init-firewall.sh +198 -0
- package/.devcontainer/post-create.sh +153 -0
- package/.dockerignore +36 -0
- package/.env.local.example +32 -0
- package/.gitattributes +83 -0
- package/.gitignore +91 -0
- package/CLAUDE.md +242 -0
- package/CODE_OF_CONDUCT.md +46 -0
- package/CONTRIBUTING.md +51 -0
- package/Dockerfile +46 -0
- package/GOVERNANCE.md +44 -0
- package/LICENSE +661 -0
- package/README.md +88 -0
- package/bin/bongos.js +222 -0
- package/clients/bongos-client/README.md +48 -0
- package/clients/bongos-client/bongos-client.global.js +617 -0
- package/clients/bongos-client/examples/hello-world.mjs +62 -0
- package/clients/bongos-client/index.cjs +619 -0
- package/clients/bongos-client/index.d.ts +793 -0
- package/clients/bongos-client/index.mjs +614 -0
- package/clients/bongos-client/package.json +32 -0
- package/config/branding.neutral.json +60 -0
- package/config/design-tokens.neutral.json +51 -0
- package/config/design-tokens.schema.json +96 -0
- package/config/modules.neutral.json +9 -0
- package/docker-compose.yml +52 -0
- package/docker-entrypoint.sh +30 -0
- package/docs/adr/0001-stack-choice-single-vps.md +45 -0
- package/docs/adr/0002-digitalocean-over-hetzner.md +27 -0
- package/docs/adr/0003-cloudflare-origin-cert-over-letsencrypt.md +35 -0
- package/docs/adr/0004-amazonprimea-name-and-trademark-acceptance.md +45 -0
- package/docs/adr/0005-invisible-other-players-in-v1.md +37 -0
- package/docs/adr/0006-singleton-worldroom-plus-queueroom.md +30 -0
- package/docs/adr/0007-persistent-identity-via-localstorage-uuid.md +31 -0
- package/docs/adr/0008-family-based-tile-generation.md +86 -0
- package/docs/adr/0008-google-chat-oauth-user-auth.md +37 -0
- package/docs/adr/0009-autotile-architecture.md +181 -0
- package/docs/adr/0010-pms-architecture.md +70 -0
- package/docs/adr/0011-terrain-id-rendering-model.md +174 -0
- package/docs/adr/0012-ground-object-cell-split.md +208 -0
- package/docs/adr/0013-paths-as-object-overlays-with-autotile-dispatch.md +158 -0
- package/docs/adr/0014-families-canonical-over-vocabulary.md +103 -0
- package/docs/adr/0015-task-dependencies-and-auto-promotion.md +125 -0
- package/docs/adr/0016-trust-boundary-server-enforced-permissions.md +132 -0
- package/docs/adr/0017-code-simplification-and-repo-cleanliness.md +74 -0
- package/docs/adr/0018-three-rank-model-goes-live.md +97 -0
- package/docs/adr/0019-red-team-bounty-payout-table.md +52 -0
- package/docs/adr/0020-security-model-public-stub.md +70 -0
- package/docs/adr/0021-per-builder-skill-model-preferences.md +99 -0
- package/docs/adr/0022-secrets-policy.md +124 -0
- package/docs/adr/0023-kind-multipliers-and-idea-bonus.md +118 -0
- package/docs/adr/0024-cloneable-repo-local-first-memory.md +277 -0
- package/docs/adr/0024-multi-agent-system-architecture.md +125 -0
- package/docs/adr/0025-offsite-backup-vendor-digitalocean-spaces.md +59 -0
- package/docs/adr/0025-structured-criterion-task-link.md +44 -0
- package/docs/adr/0026-bfg-memory-hygiene-and-cross-builder-learning.md +117 -0
- package/docs/adr/0027-bfg-session-inefficiency-evaluator.md +170 -0
- package/docs/adr/0028-honest-llm-spend-accounting.md +109 -0
- package/docs/adr/0029-status-page-outage-resilience.md +59 -0
- package/docs/adr/0030-builders-hall-live-updates.md +59 -0
- package/docs/adr/0031-cloud-dev-environments-for-builders.md +222 -0
- package/docs/adr/0032-discord-mirror-of-gds.md +50 -0
- package/docs/adr/0033-discord-bot-service-principal.md +82 -0
- package/docs/adr/0034-thetes-graduated-newcomer-rank.md +53 -0
- package/docs/adr/0035-builder-onboarding-three-paths.md +128 -0
- package/docs/adr/0036-builders-subdomain-and-ui-reorg.md +40 -0
- package/docs/adr/0037-discord-channel-management.md +51 -0
- package/docs/adr/0038-chromebook-ttyd-cloudflare-tunnel.md +111 -0
- package/docs/adr/0039-setup-first-onboarding-ux.md +49 -0
- package/docs/adr/0040-remote-control-default-browser-onramp.md +47 -0
- package/docs/adr/0041-temporary-grader-bypass-killswitch.md +40 -0
- package/docs/adr/0042-builder-self-deploy-ci-auto-merge.md +82 -0
- package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +74 -0
- package/docs/adr/0044-mediterranean-palette-replacement.md +73 -0
- package/docs/adr/0044-per-box-live-game-preview.md +57 -0
- package/docs/adr/0045-devbox-desktop-app.md +133 -0
- package/docs/adr/0046-sandbox-first-review-gate.md +72 -0
- package/docs/adr/0047-discord-bugs-intake-anti-abuse.md +36 -0
- package/docs/adr/0048-works-in-progress-ia-split.md +32 -0
- package/docs/adr/0049-split-parallel-safety-contract.md +46 -0
- package/docs/adr/0050-device-flow-admission-invite-gated-by-default.md +43 -0
- package/docs/adr/0051-full-session-transcript-corpus.md +57 -0
- package/docs/adr/0052-sandbox-for-everyone-game-only-preview.md +70 -0
- package/docs/adr/0053-scoped-dev-box-session.md +55 -0
- package/docs/adr/0054-session-token-reward-cost-plus.md +63 -0
- package/docs/adr/0055-server-mediated-branch-publish.md +47 -0
- package/docs/adr/0056-prod-deploy-script-mirror-and-healthcheck-retry.md +62 -0
- package/docs/adr/0057-container-cost-ledger.md +28 -0
- package/docs/adr/0057-discord-archon-approval-channels.md +64 -0
- package/docs/adr/0058-automatic-gate-surface-gatekeeper.md +64 -0
- package/docs/adr/0059-single-approval-remove-devbox-approval-gate.md +37 -0
- package/docs/adr/0060-gds-retrieval-layer.md +97 -0
- package/docs/adr/0061-context-layer-decomposition.md +61 -0
- package/docs/adr/0062-medusa-instance-model-decoupling.md +107 -0
- package/docs/adr/0063-generated-repo-map-symbol-skeleton.md +44 -0
- package/docs/adr/0064-rename-medusa-to-cloud-bongos.md +49 -0
- package/docs/adr/0065-agpl-nonprofit-ai-first-governance.md +69 -0
- package/docs/adr/0066-generated-file-map-sections.md +51 -0
- package/docs/adr/0067-session-start-fast-forward-pull.md +43 -0
- package/docs/adr/0068-shared-art-key-for-newcomers.md +38 -0
- package/docs/adr/0069-hall-live-channel-sse-decouple.md +35 -0
- package/docs/adr/0070-deterministic-session-card-delivery.md +44 -0
- package/docs/adr/0071-box-confirm-before-destroyed-and-drift-reconcile.md +59 -0
- package/docs/adr/0072-bongos-app-mac-signed-first-windows-deferred.md +35 -0
- package/docs/adr/0072-dev-box-code-staleness-visibility.md +39 -0
- package/docs/adr/0073-builder-needs-signal-and-byok-gemini-key.md +64 -0
- package/docs/adr/0073-secrets-scan-exclude-uri-detector.md +37 -0
- package/docs/adr/0074-memory-map-stays-light.md +32 -0
- package/docs/adr/0075-per-system-cost-attribution.md +37 -0
- package/docs/adr/0076-in-session-deterministic-compaction.md +58 -0
- package/docs/adr/0077-content-addressed-llm-cache.md +32 -0
- package/docs/adr/0078-deterministic-first-cron.md +48 -0
- package/docs/adr/0079-value-gated-autonomous-engagement.md +39 -0
- package/docs/adr/0080-llm-cache-api-transport-and-trust-model.md +46 -0
- package/docs/adr/0081-tool-agnostic-design-layer.md +62 -0
- package/docs/adr/0082-productized-key-storage-provisioning.md +32 -0
- package/docs/adr/0082-server-side-merge-conflict-auto-resolution.md +55 -0
- package/docs/adr/0083-modular-architecture-strangler-build-plan.md +143 -0
- package/docs/adr/0084-auto-derived-per-task-rank-floor.md +86 -0
- package/docs/adr/0085-remove-default-per-builder-spend-cap.md +39 -0
- package/docs/adr/0086-goal-scoped-work-hierarchy.md +123 -0
- package/docs/adr/0087-bongos-app-architecture-and-handoff-contract.md +49 -0
- package/docs/adr/0087-compete-on-governance-not-tooling-cursor.md +65 -0
- package/docs/adr/0088-consistent-character-generative-animation.md +169 -0
- package/docs/adr/0089-modular-multi-model-adversarial-grader.md +179 -0
- package/docs/adr/0090-metic-task-authoring.md +73 -0
- package/docs/adr/0091-bounding-the-kernel-and-db-carve.md +106 -0
- package/docs/adr/0092-hosting-module-and-on-prem-target.md +117 -0
- package/docs/adr/0093-tranche-2-core-carve-sequence.md +72 -0
- package/docs/adr/0094-repo-atlas-self-drawing-codebase-map.md +49 -0
- package/docs/adr/0095-borrowed-memory-and-retrieval-concepts.md +65 -0
- package/docs/adr/0095-cross-agent-context-management.md +58 -0
- package/docs/adr/0096-require-reward-before-workable.md +209 -0
- package/docs/adr/0097-one-active-claim-per-session-and-worktree-binding.md +46 -0
- package/docs/adr/0097-retroactive-reward-backfill.md +124 -0
- package/docs/adr/0098-public-mirror-publish-manifest.md +92 -0
- package/docs/adr/0099-delayed-redacted-mirror-export.md +55 -0
- package/docs/adr/0100-two-repo-instance-model.md +60 -0
- package/docs/adr/0101-goal-hierarchy-phase-5-judge-membership-reward.md +90 -0
- package/docs/adr/0102-finish-bounding-the-kernel.md +36 -0
- package/docs/adr/0103-core-first-extraction-cloud-bongos-trunk.md +70 -0
- package/docs/adr/0103-gdsv4-bongos-consolidation.md +28 -0
- package/docs/adr/0104-trust-gds-api-channel-in-auto-mode.md +42 -0
- package/docs/adr/0105-instance-seed-migrations-out-of-core.md +47 -0
- package/docs/adr/0106-goal-owner-manager-authority.md +84 -0
- package/docs/adr/0107-module-upstreaming-contribution-to-core-catalog.md +83 -0
- package/docs/adr/0108-instance-composition-configurable-root.md +87 -0
- package/docs/adr/0109-self-describing-openapi-and-hosted-docs.md +44 -0
- package/docs/adr/0110-untrack-whole-file-generated-nav-docs.md +49 -0
- package/docs/adr/0111-instance-hosting-provisioning-module.md +135 -0
- package/docs/adr/0112-private-goals-invitations-join-requests.md +72 -0
- package/docs/adr/0113-sandbox-studio-descope-superseded-by-0044-0052.md +41 -0
- package/docs/adr/0114-instance-docs-discovery-contract.md +32 -0
- package/docs/adr/0115-scheduled-routines-portability.md +31 -0
- package/docs/adr/0116-api-error-envelope-and-code-taxonomy.md +62 -0
- package/docs/adr/0117-api-versioning-and-deprecation-policy.md +50 -0
- package/docs/adr/0118-api-contract-source-of-truth-code-first.md +47 -0
- package/docs/adr/0119-api-pagination-contract.md +34 -0
- package/docs/adr/0120-pay-on-land-and-builder-owned-rebase-gate.md +108 -0
- package/docs/adr/0121-greenfield-vs-brownfield-onboarding-adopt-existing-repo.md +97 -0
- package/docs/adr/0122-onboarding-diagram-renders-deploy-rendered-off-git.md +43 -0
- package/docs/adr/0123-box-idle-sweep-autosave-before-destroy.md +36 -0
- package/docs/adr/0124-typed-api-response-bodies.md +37 -0
- package/docs/adr/0125-control-plane-scaffolds-standalone-instance-repo.md +36 -0
- package/docs/adr/0126-dedicated-cloudbongos-control-plane-droplet.md +30 -0
- package/docs/adr/0127-cross-box-fleet-observability.md +64 -0
- package/docs/adr/0128-provisioning-runner-privilege-and-db-auth-model.md +46 -0
- package/docs/adr/0129-cloudbongos-control-plane-pull-deploy.md +34 -0
- package/docs/adr/0130-provision-remote-exec-over-ssh.md +61 -0
- package/docs/adr/0131-rank-scoped-skill-visibility.md +47 -0
- package/docs/adr/0132-cohost-fleet-control-plane-migration.md +54 -0
- package/docs/adr/0133-github-app-manifest-onboarding-signin.md +42 -0
- package/docs/adr/0134-private-first-npm-distribution.md +38 -0
- package/docs/adr/README.md +208 -0
- package/docs/api/openapi.json +13720 -0
- package/docs/api-reference.md +437 -0
- package/docs/architecture.md +244 -0
- package/docs/branding-contract.md +66 -0
- package/docs/branding-fill-prompt.md +25 -0
- package/docs/canonical-permissions.md +241 -0
- package/docs/design/container-exterior-tiles.md +49 -0
- package/docs/design/container-exterior.md +81 -0
- package/docs/design/container-interior.md +77 -0
- package/docs/design/modular-architecture/00-research-report.md +107 -0
- package/docs/design/modular-architecture/01-architecture.md +125 -0
- package/docs/design/modular-architecture/02-module-map.md +116 -0
- package/docs/design/modular-architecture/03-builder-flows.md +104 -0
- package/docs/design/modular-architecture/04-module-lifecycle.md +62 -0
- package/docs/design/modular-architecture/README.md +27 -0
- package/docs/design/vanilla-hall-ui-redesign-scope.md +284 -0
- package/docs/design/world-map-scroll.md +41 -0
- package/docs/design-contract.md +320 -0
- package/docs/file-map.md +418 -0
- package/docs/handoff-template.md +92 -0
- package/docs/modules-contract.md +293 -0
- package/docs/onboarding/browser-terminal-guide.md +73 -0
- package/docs/onboarding/diagrams/01-task-lifecycle.mmd +28 -0
- package/docs/onboarding/diagrams/02-rank-ladder.mmd +54 -0
- package/docs/onboarding/diagrams/03-drachmae-karma.mmd +37 -0
- package/docs/onboarding/diagrams/04-architecture.mmd +51 -0
- package/docs/onboarding/diagrams/05-versioning.mmd +29 -0
- package/docs/onboarding/diagrams/README.md +94 -0
- package/docs/onboarding/diagrams/assertions.json +170 -0
- package/docs/onboarding/diagrams/puppeteer-config.json +1 -0
- package/docs/onboarding/diagrams/render-config.json +9 -0
- package/docs/onboarding/drachmae-and-karma.md +178 -0
- package/docs/onboarding/primer.md +202 -0
- package/docs/project-context.template.md +67 -0
- package/docs/recipes/README.md +35 -0
- package/docs/recipes/audit-replay.md +100 -0
- package/docs/recipes/bongos-cli-release.md +66 -0
- package/docs/recipes/builder-box-lifecycle.md +152 -0
- package/docs/recipes/claude-design-loop.md +143 -0
- package/docs/recipes/claude-gemini-bongos-doors.md +155 -0
- package/docs/recipes/cloudbongos-staging-gate.md +139 -0
- package/docs/recipes/cloudbongos-standup.md +111 -0
- package/docs/recipes/devbox-app-release.md +93 -0
- package/docs/recipes/devbox-app-windows-test.md +128 -0
- package/docs/recipes/failed-ship-recovery-proof.md +102 -0
- package/docs/recipes/figma-design-loop.md +129 -0
- package/docs/recipes/gds-db-backup.md +255 -0
- package/docs/recipes/instance-deploy.md +37 -0
- package/docs/recipes/managed-settings-remote-control.md +416 -0
- package/docs/recipes/memory-backup.md +71 -0
- package/docs/recipes/memory-sync-conflicts.md +98 -0
- package/docs/recipes/multi-builder-merge.md +78 -0
- package/docs/recipes/ops-gotchas.md +212 -0
- package/docs/recipes/overnight-builder.md +53 -0
- package/docs/recipes/packaging-the-core.md +49 -0
- package/docs/recipes/parallel-load-results-2026-05-30.md +63 -0
- package/docs/recipes/parallel-load-test.md +32 -0
- package/docs/recipes/pixel-art-pipeline.md +411 -0
- package/docs/recipes/private-npm-distribution.md +79 -0
- package/docs/recipes/search-index-ingestion.md +67 -0
- package/docs/recipes/self-host.md +60 -0
- package/docs/recipes/ship-and-regrade.md +72 -0
- package/docs/recipes/staging-data.md +50 -0
- package/docs/recipes/staging-environment.md +215 -0
- package/docs/recipes/upgrading-the-core.md +58 -0
- package/docs/research/cursor-competitive-analysis.md +255 -0
- package/docs/research/llm-model-agnostic-and-cheaper-grader.md +227 -0
- package/migrations/003_pms.sql +284 -0
- package/migrations/004_pms_cost_idempotency.sql +13 -0
- package/migrations/005_pms_smoke_filter.sql +44 -0
- package/migrations/006_pms_v2.sql +378 -0
- package/migrations/007_pms_v2_hierarchy_trigger.sql +59 -0
- package/migrations/008_pms_v2_migration_allocator.sql +27 -0
- package/migrations/009_pms_v2_blockers_table.sql +68 -0
- package/migrations/010_uptime.sql +29 -0
- package/migrations/011_backfill_v2_v3_done_when.sql +20 -0
- package/migrations/012_pms_v2_task_lifecycle_states.sql +82 -0
- package/migrations/013_claim_locking.sql +22 -0
- package/migrations/014_pms_task_discipline.sql +86 -0
- package/migrations/015_pms_estimation_calibration.sql +140 -0
- package/migrations/016_pms_task_grades.sql +60 -0
- package/migrations/017_version_progress_exclude_abandoned.sql +49 -0
- package/migrations/019_rename_pms_v3_to_gds_v3.sql +65 -0
- package/migrations/020_task_dependencies.sql +99 -0
- package/migrations/021_v3_renumber_and_deps.sql +224 -0
- package/migrations/022_v3_reconcile_dep_gated_status.sql +41 -0
- package/migrations/023_pms_rank.sql +30 -0
- package/migrations/025_builder_exit_status.sql +15 -0
- package/migrations/027_builders_preferred_disciplines.sql +46 -0
- package/migrations/028_tasks_parallel_safe.sql +71 -0
- package/migrations/029_rank_three_live.sql +32 -0
- package/migrations/030_vulnerability_reports.sql +61 -0
- package/migrations/031_reward_simplification.sql +57 -0
- package/migrations/032_repo_health_snapshots.sql +56 -0
- package/migrations/033_audit_log.sql +64 -0
- package/migrations/034_lifecycle_breakdown_leaf_only.sql +62 -0
- package/migrations/035_auth_token_hygiene.sql +66 -0
- package/migrations/037_builder_skill_model_prefs.sql +44 -0
- package/migrations/038_task_override_requests.sql +51 -0
- package/migrations/039_newcomer_friendly_column.sql +124 -0
- package/migrations/040_builder_karma.sql +58 -0
- package/migrations/041_kind_multipliers_and_idea_bonus.sql +42 -0
- package/migrations/042_criterion_proposal_workflow.sql +78 -0
- package/migrations/043_builder_onboarding_observability.sql +66 -0
- package/migrations/044_tasks_requires_rank.sql +97 -0
- package/migrations/045_builder_onboarding_state.sql +147 -0
- package/migrations/046_cost_log_builder_attribution.sql +42 -0
- package/migrations/054_builder_memory.sql +108 -0
- package/migrations/055_task_criteria.sql +90 -0
- package/migrations/058_peer_votes.sql +41 -0
- package/migrations/059_onboarding_pick_disciplines.sql +59 -0
- package/migrations/060_access_requests.sql +46 -0
- package/migrations/061_backfill_override_ship_attribution.sql +29 -0
- package/migrations/062_session_records.sql +34 -0
- package/migrations/063_session_records_tool_errors_idx.sql +11 -0
- package/migrations/064_grade_attempts.sql +18 -0
- package/migrations/065_bfg_principal.sql +58 -0
- package/migrations/066_live_notify_triggers.sql +69 -0
- package/migrations/067_builder_boxes.sql +117 -0
- package/migrations/067_discord_bot_foundation.sql +69 -0
- package/migrations/068_thetes_requires_rank.sql +27 -0
- package/migrations/069_builder_ssh_keys.sql +66 -0
- package/migrations/070_box_intents.sql +101 -0
- package/migrations/071_box_first_provision_approval.sql +46 -0
- package/migrations/072_onboarding_ship_three_remove_primer.sql +80 -0
- package/migrations/073_box_terminal_access.sql +46 -0
- package/migrations/075_builder_sound_prefs.sql +28 -0
- package/migrations/078_box_claude_active.sql +22 -0
- package/migrations/079_box_first_connected_at.sql +20 -0
- package/migrations/081_tasks_needs_migration.sql +34 -0
- package/migrations/084_tasks_security_sensitive.sql +24 -0
- package/migrations/085_security_engagement_docs.sql +34 -0
- package/migrations/086_rename_disciplines.sql +125 -0
- package/migrations/088_builders_anthropic_link.sql +28 -0
- package/migrations/089_builders_monthly_budget.sql +19 -0
- package/migrations/090_box_scoped_sessions.sql +38 -0
- package/migrations/091_session_token_reward.sql +44 -0
- package/migrations/093_tasks_sandbox_review.sql +22 -0
- package/migrations/102_remove_box_first_provision_approval.sql +58 -0
- package/migrations/103_search_chunks.sql +90 -0
- package/migrations/104_builder_box_blocked.sql +34 -0
- package/migrations/105_box_host_keys.sql +35 -0
- package/migrations/111_medusa_customer0_framing.sql +35 -0
- package/migrations/112_drop_track_check.sql +25 -0
- package/migrations/113_merge_lease.sql +16 -0
- package/migrations/114_cloudbongos_rename_live_strings.sql +32 -0
- package/migrations/118_currency_label_decoupling.sql +23 -0
- package/migrations/119_builder_behavior_prefs.sql +31 -0
- package/migrations/121_box_code_version.sql +37 -0
- package/migrations/122_builder_gemini_key.sql +30 -0
- package/migrations/123_cost_log_tiers.sql +33 -0
- package/migrations/124_cost_baseline.sql +45 -0
- package/migrations/125_llm_cache.sql +54 -0
- package/migrations/126_autonomy_runs.sql +33 -0
- package/migrations/143_cost_calibration.sql +63 -0
- package/migrations/145_backfill_task_requires_rank.sql +84 -0
- package/migrations/160_goal_tier.sql +88 -0
- package/migrations/163_polymorphic_dependencies.sql +187 -0
- package/migrations/164_event_sound_prefs.sql +20 -0
- package/migrations/165_task_module_key.sql +15 -0
- package/migrations/171_claims_published_head_sha.sql +24 -0
- package/migrations/174_close_orphaned_claims_on_terminal_tasks.sql +30 -0
- package/migrations/175_task_grades_diff_hash.sql +9 -0
- package/migrations/176_promotion_respects_open_blockers.sql +58 -0
- package/migrations/176_ui_discipline.sql +40 -0
- package/migrations/177_require_reward_before_workable.sql +76 -0
- package/migrations/178_reward_gate_auto_assign_revert_autopromote.sql +61 -0
- package/migrations/179_search_chunk_usefulness.sql +33 -0
- package/migrations/180_one_active_claim_per_session.sql +54 -0
- package/migrations/181_cost_log_skill_name.sql +33 -0
- package/migrations/184_claim_release_requested.sql +25 -0
- package/migrations/185_module_upstreaming_goal_wiring.sql +59 -0
- package/migrations/187_goal_sort_order.sql +30 -0
- package/migrations/187_tasks_kind_check_add_verify.sql +21 -0
- package/migrations/README.md +88 -0
- package/migrations/core_188_goal_visibility_and_membership_requests.sql +71 -0
- package/migrations/core_189_core_upgrades_ledger.sql +37 -0
- package/migrations/core_189_credit_log_task_id_index.sql +19 -0
- package/migrations/core_190_rebuild_claimable_task_views.sql +71 -0
- package/migrations/instance/018_pms_v3_planning_seed.sql +131 -0
- package/migrations/instance/080_gds_v4_planning_seed.sql +75 -0
- package/migrations/instance/110_medusa_planning_seed.sql +70 -0
- package/migrations/instance/120_bongos_v1_planning_seed.sql +69 -0
- package/migrations/instance/144_bongos_v1_module_system_criterion.sql +26 -0
- package/migrations/instance/159_bongos_v1_goal_hierarchy_criterion.sql +29 -0
- package/migrations/instance/172_v2_world_planning_seed.sql +163 -0
- package/migrations/instance/173_bongos_v1_c7_core_modularized.sql +33 -0
- package/migrations/instance/182_gdsv4_bongos_consolidation.sql +132 -0
- package/migrations/instance/183_gdsv4_carryover_themed_goals.sql +116 -0
- package/migrations/instance/186_bongos_v1_governance_planning_seed.sql +69 -0
- package/modules/autonomy/CLAUDE.md +49 -0
- package/modules/autonomy/db.js +50 -0
- package/modules/autonomy/module.json +13 -0
- package/modules/autonomy/pollers/routine-timers.js +146 -0
- package/modules/autonomy/routes/autonomy.js +37 -0
- package/modules/builder-settings/CLAUDE.md +58 -0
- package/modules/builder-settings/builder-needs.js +115 -0
- package/modules/builder-settings/db.js +168 -0
- package/modules/builder-settings/display-name.js +84 -0
- package/modules/builder-settings/event-sound-prefs.js +169 -0
- package/modules/builder-settings/interaction-prefs.js +201 -0
- package/modules/builder-settings/model-alloc-prefs.js +147 -0
- package/modules/builder-settings/module.json +10 -0
- package/modules/builder-settings/render-prefs.js +103 -0
- package/modules/builder-settings/routes/settings.js +417 -0
- package/modules/builder-settings/settings.js +52 -0
- package/modules/builder-settings/skill-prefs.js +196 -0
- package/modules/builder-settings/sound-prefs.js +178 -0
- package/modules/builder-settings/wandering-prefs.js +282 -0
- package/modules/dev-box/CLAUDE.md +38 -0
- package/modules/dev-box/box-access.js +275 -0
- package/modules/dev-box/box-credential.js +94 -0
- package/modules/dev-box/box-onboard.js +486 -0
- package/modules/dev-box/boxes.js +842 -0
- package/modules/dev-box/db.js +39 -0
- package/modules/dev-box/module.json +14 -0
- package/modules/dev-box/routes/box.js +977 -0
- package/modules/discord/CLAUDE.md +50 -0
- package/modules/discord/auth.js +54 -0
- package/modules/discord/bug-attachments.js +210 -0
- package/modules/discord/db.js +96 -0
- package/modules/discord/discord-approvals.js +145 -0
- package/modules/discord/discord-audit.js +29 -0
- package/modules/discord/discord-bot.js +545 -0
- package/modules/discord/discord-bugs.js +257 -0
- package/modules/discord/discord-channels.js +412 -0
- package/modules/discord/discord-inbound.js +147 -0
- package/modules/discord/discord-message-buffer.js +54 -0
- package/modules/discord/discord-reaction.js +186 -0
- package/modules/discord/discord-role-sync.js +318 -0
- package/modules/discord/module.json +14 -0
- package/modules/discord/pollers/discord-bot.js +19 -0
- package/modules/discord/routes/bug-attachments.js +44 -0
- package/modules/discord/routes/discord.js +102 -0
- package/modules/discord/ship-broadcast.js +78 -0
- package/modules/discord/webhook.js +74 -0
- package/modules/economy/CLAUDE.md +48 -0
- package/modules/economy/achievements.js +594 -0
- package/modules/economy/cost-classify.js +331 -0
- package/modules/economy/cost-summary-shape.js +90 -0
- package/modules/economy/cost.js +438 -0
- package/modules/economy/credits.js +430 -0
- package/modules/economy/migrations/economy_001_fix_gds_shipper_description.sql +91 -0
- package/modules/economy/module.json +10 -0
- package/modules/economy/reward.js +61 -0
- package/modules/economy/routes/cost.js +97 -0
- package/modules/economy/routes/leaderboard.js +26 -0
- package/modules/economy/routes/reward.js +42 -0
- package/modules/economy/streak.js +285 -0
- package/modules/grading/CLAUDE.md +42 -0
- package/modules/grading/db.js +39 -0
- package/modules/grading/grader-rubric.json +151 -0
- package/modules/grading/grader-workers/efficiency.js +213 -0
- package/modules/grading/grader-workers/extract-json.js +80 -0
- package/modules/grading/grader-workers/fence.js +100 -0
- package/modules/grading/grader-workers/hacker.js +239 -0
- package/modules/grading/grader-workers/index.js +183 -0
- package/modules/grading/grader-workers/narc.js +207 -0
- package/modules/grading/grader-workers/quality.js +198 -0
- package/modules/grading/grader-workers/rubric.js +20 -0
- package/modules/grading/grader-workers/worker-prompt.js +89 -0
- package/modules/grading/grader-workers/worker-verdict.js +50 -0
- package/modules/grading/grader.js +1790 -0
- package/modules/grading/module.json +12 -0
- package/modules/grading/routes/grade.js +51 -0
- package/modules/hall-ui/CLAUDE.md +61 -0
- package/modules/hall-ui/module.json +14 -0
- package/modules/hall-ui/public/atlas.html +180 -0
- package/modules/hall-ui/public/atlas.js +336 -0
- package/modules/hall-ui/public/box-panel.js +423 -0
- package/modules/hall-ui/public/brand-apply.js +117 -0
- package/modules/hall-ui/public/builders.js +3028 -0
- package/modules/hall-ui/public/chime.wav +0 -0
- package/modules/hall-ui/public/copy-on-click.js +174 -0
- package/modules/hall-ui/public/cursors/arrow.png +0 -0
- package/modules/hall-ui/public/cursors/hand-pointer.png +0 -0
- package/modules/hall-ui/public/cursors/magnifier-out.png +0 -0
- package/modules/hall-ui/public/cursors/magnifier.png +0 -0
- package/modules/hall-ui/public/diagram-viewer.css +125 -0
- package/modules/hall-ui/public/diagram-viewer.js +330 -0
- package/modules/hall-ui/public/diagrams.html +113 -0
- package/modules/hall-ui/public/dom-utils.js +212 -0
- package/modules/hall-ui/public/drachmae.html +68 -0
- package/modules/hall-ui/public/drachmae.js +136 -0
- package/modules/hall-ui/public/gate.html +143 -0
- package/modules/hall-ui/public/gate.js +228 -0
- package/modules/hall-ui/public/goals-page.js +1297 -0
- package/modules/hall-ui/public/goals.html +376 -0
- package/modules/hall-ui/public/goals.js +119 -0
- package/modules/hall-ui/public/hall-widgets.js +189 -0
- package/modules/hall-ui/public/harbor.html +167 -0
- package/modules/hall-ui/public/harbor.js +335 -0
- package/modules/hall-ui/public/index.html +116 -0
- package/modules/hall-ui/public/instances-panel.js +172 -0
- package/modules/hall-ui/public/md-reader.js +234 -0
- package/modules/hall-ui/public/modules.html +119 -0
- package/modules/hall-ui/public/modules.js +154 -0
- package/modules/hall-ui/public/new-project-wizard.js +186 -0
- package/modules/hall-ui/public/not-ready.html +48 -0
- package/modules/hall-ui/public/pair.html +119 -0
- package/modules/hall-ui/public/pair.js +132 -0
- package/modules/hall-ui/public/primer.css +404 -0
- package/modules/hall-ui/public/primer.html +85 -0
- package/modules/hall-ui/public/primer.js +641 -0
- package/modules/hall-ui/public/profile.html +85 -0
- package/modules/hall-ui/public/profile.js +236 -0
- package/modules/hall-ui/public/ranks.html +69 -0
- package/modules/hall-ui/public/ranks.js +206 -0
- package/modules/hall-ui/public/roadmap.html +209 -0
- package/modules/hall-ui/public/roadmap.js +375 -0
- package/modules/hall-ui/public/sessions.html +92 -0
- package/modules/hall-ui/public/sessions.js +222 -0
- package/modules/hall-ui/public/settings.html +640 -0
- package/modules/hall-ui/public/settings.js +1219 -0
- package/modules/hall-ui/public/shell.js +495 -0
- package/modules/hall-ui/public/style.css +1748 -0
- package/modules/hall-ui/public/task-detail.js +253 -0
- package/modules/hall-ui/public/task.html +83 -0
- package/modules/hall-ui/public/task.js +326 -0
- package/modules/hall-ui/public/watch.html +333 -0
- package/modules/hall-ui/public/watch.js +859 -0
- package/modules/hall-ui/public/work.html +469 -0
- package/modules/hall-ui/public/work.js +1292 -0
- package/modules/ideas/CLAUDE.md +37 -0
- package/modules/ideas/blockers.js +100 -0
- package/modules/ideas/inbox.js +459 -0
- package/modules/ideas/module.json +10 -0
- package/modules/ideas/routes/blockers.js +120 -0
- package/modules/ideas/routes/inbox.js +230 -0
- package/modules/lifecycle/CLAUDE.md +63 -0
- package/modules/lifecycle/conflict-resolve.js +436 -0
- package/modules/lifecycle/db.js +4970 -0
- package/modules/lifecycle/done-when.js +355 -0
- package/modules/lifecycle/github-push.js +969 -0
- package/modules/lifecycle/goal-conflicts.js +133 -0
- package/modules/lifecycle/hierarchy.js +104 -0
- package/modules/lifecycle/lifecycle.js +58 -0
- package/modules/lifecycle/merge-lock.js +261 -0
- package/modules/lifecycle/migrations/lifecycle_001_goal_first_leads.sql +28 -0
- package/modules/lifecycle/migrations/lifecycle_002_backfill_orphan_task_goals.sql +36 -0
- package/modules/lifecycle/module.json +13 -0
- package/modules/lifecycle/pollers/publish-reconciler.js +20 -0
- package/modules/lifecycle/publish-reconciler.js +418 -0
- package/modules/lifecycle/routes/analytics.js +63 -0
- package/modules/lifecycle/routes/claims.js +506 -0
- package/modules/lifecycle/routes/dependencies.js +82 -0
- package/modules/lifecycle/routes/done-when.js +136 -0
- package/modules/lifecycle/routes/gate-approvals.js +197 -0
- package/modules/lifecycle/routes/goals.js +1419 -0
- package/modules/lifecycle/routes/lifecycle.js +43 -0
- package/modules/lifecycle/routes/tasks.js +1703 -0
- package/modules/lifecycle/routes/versions.js +128 -0
- package/modules/lifecycle/ship-card.js +505 -0
- package/modules/lifecycle/ship-preflight.js +225 -0
- package/modules/lifecycle/task-classifier.js +512 -0
- package/modules/lifecycle/version-close.js +106 -0
- package/modules/memory/CLAUDE.md +40 -0
- package/modules/memory/learnings.js +275 -0
- package/modules/memory/memory.js +572 -0
- package/modules/memory/module.json +12 -0
- package/modules/memory/routes/learnings.js +90 -0
- package/modules/memory/routes/memory.js +916 -0
- package/modules/memory/routes/search.js +188 -0
- package/modules/memory/search-chunker.js +252 -0
- package/modules/memory/search.js +320 -0
- package/modules/onboarding/CLAUDE.md +55 -0
- package/modules/onboarding/approval-broadcast.js +59 -0
- package/modules/onboarding/db.js +54 -0
- package/modules/onboarding/module.json +10 -0
- package/modules/onboarding/newcomer-restock.js +212 -0
- package/modules/onboarding/onboarding-state.js +532 -0
- package/modules/onboarding/onboarding.js +508 -0
- package/modules/onboarding/port.js +63 -0
- package/modules/onboarding/routes/access-requests.js +208 -0
- package/modules/onboarding/routes/onboarding.js +54 -0
- package/modules/security/CLAUDE.md +44 -0
- package/modules/security/module.json +10 -0
- package/modules/security/routes/reports.js +251 -0
- package/modules/security/secret-scrub.js +201 -0
- package/modules/security/security.js +294 -0
- package/modules/sessions/CLAUDE.md +39 -0
- package/modules/sessions/bfg.js +357 -0
- package/modules/sessions/db.js +326 -0
- package/modules/sessions/module.json +10 -0
- package/modules/sessions/pulse.js +149 -0
- package/modules/sessions/routes/sessions.js +331 -0
- package/modules/status-ui/CLAUDE.md +47 -0
- package/modules/status-ui/module.json +14 -0
- package/modules/status-ui/public/README.md +29 -0
- package/modules/status-ui/public/cursors/arrow.png +0 -0
- package/modules/status-ui/public/cursors/hand-pointer.png +0 -0
- package/modules/status-ui/public/index.html +363 -0
- package/modules/status-ui/public/snapshots/.gitkeep +0 -0
- package/modules/status-ui/public/status.js +1375 -0
- package/modules/status-ui/public/style.css +1342 -0
- package/package-lock.json +975 -0
- package/package.json +28 -0
- package/public-docs/index.html +35 -0
- package/public-docs/redoc.standalone.js +1838 -0
- package/public-docs/redoc.standalone.js.LICENSE.txt +102 -0
- package/public-landing/buddha.png +0 -0
- package/public-landing/create.html +868 -0
- package/public-landing/index.html +168 -0
- package/scripts/bongos-mcp.js +28 -0
- package/scripts/cron/style_guide_audit.sh +134 -0
- package/scripts/discord/README.md +52 -0
- package/scripts/discord/lib.js +80 -0
- package/scripts/discord/post.js +51 -0
- package/scripts/gds/CLAUDE.md +144 -0
- package/scripts/gds/abandon.js +58 -0
- package/scripts/gds/adopt-detect.js +123 -0
- package/scripts/gds/adopt-import.js +111 -0
- package/scripts/gds/adopt-preflight.js +121 -0
- package/scripts/gds/api.js +78 -0
- package/scripts/gds/architect-audit.js +288 -0
- package/scripts/gds/art-stage.js +152 -0
- package/scripts/gds/audit-authorship.sh +243 -0
- package/scripts/gds/audit-deps.js +121 -0
- package/scripts/gds/audit-exports.js +128 -0
- package/scripts/gds/audit-replay.sh +161 -0
- package/scripts/gds/audit-ships.js +251 -0
- package/scripts/gds/autonomy-gate.js +135 -0
- package/scripts/gds/backfill-cost.js +165 -0
- package/scripts/gds/backfill-sessions.js +351 -0
- package/scripts/gds/backfill-task-rewards.js +408 -0
- package/scripts/gds/backup.js +94 -0
- package/scripts/gds/bfg-principal-token.js +65 -0
- package/scripts/gds/box-auth-check.js +160 -0
- package/scripts/gds/box-connect-lib.js +453 -0
- package/scripts/gds/box.js +1258 -0
- package/scripts/gds/build-bongos.js +94 -0
- package/scripts/gds/capture.js +123 -0
- package/scripts/gds/cf-tunnel.js +419 -0
- package/scripts/gds/ci-grade.js +82 -0
- package/scripts/gds/claim-recall.js +112 -0
- package/scripts/gds/claim.js +333 -0
- package/scripts/gds/classify-discipline.js +153 -0
- package/scripts/gds/claude-materialize.js +176 -0
- package/scripts/gds/cleanup-orphans.js +74 -0
- package/scripts/gds/cli-lib.js +518 -0
- package/scripts/gds/code.js +101 -0
- package/scripts/gds/codemod-rename-src-gds.js +145 -0
- package/scripts/gds/conductor-dispatch.js +426 -0
- package/scripts/gds/context-pack.js +228 -0
- package/scripts/gds/coreB-carve-proof.sh +716 -0
- package/scripts/gds/cost.js +47 -0
- package/scripts/gds/db-backup-nightly.sh +160 -0
- package/scripts/gds/db-backup-offsite.sh +152 -0
- package/scripts/gds/demote.js +40 -0
- package/scripts/gds/design-sync.js +62 -0
- package/scripts/gds/diagnose-achievements.js +118 -0
- package/scripts/gds/diagram-facts.js +319 -0
- package/scripts/gds/discipline-modes.json +25 -0
- package/scripts/gds/discord-channels.js +66 -0
- package/scripts/gds/do-api.js +176 -0
- package/scripts/gds/docs-entropy.js +403 -0
- package/scripts/gds/doctor.js +389 -0
- package/scripts/gds/feedback-latest.js +94 -0
- package/scripts/gds/fetch-art-key.js +106 -0
- package/scripts/gds/fetch-sound-prefs.js +88 -0
- package/scripts/gds/figma-design-sync.js +61 -0
- package/scripts/gds/fitness.js +1446 -0
- package/scripts/gds/gate-review.js +322 -0
- package/scripts/gds/gating.js +325 -0
- package/scripts/gds/gds-db-backup.service +24 -0
- package/scripts/gds/gds-db-backup.timer +20 -0
- package/scripts/gds/gds-db-offsite.service +29 -0
- package/scripts/gds/gds-db-offsite.timer +18 -0
- package/scripts/gds/gen-api-client.js +508 -0
- package/scripts/gds/gen-api-docs.js +1037 -0
- package/scripts/gds/gen-atlas.js +366 -0
- package/scripts/gds/gen-diagrams.js +608 -0
- package/scripts/gds/gen-file-map.js +196 -0
- package/scripts/gds/gen-repo-map.js +519 -0
- package/scripts/gds/gen-session-index.js +210 -0
- package/scripts/gds/git-merge-regen.js +147 -0
- package/scripts/gds/grade-smoke.js +205 -0
- package/scripts/gds/hooks/pre-push.js +169 -0
- package/scripts/gds/http-api-client.js +88 -0
- package/scripts/gds/init.js +903 -0
- package/scripts/gds/install-git-hooks.js +114 -0
- package/scripts/gds/key-card.js +213 -0
- package/scripts/gds/key-status.js +126 -0
- package/scripts/gds/land-watch.js +168 -0
- package/scripts/gds/learning-capture.js +145 -0
- package/scripts/gds/lib.sh +44 -0
- package/scripts/gds/linkify-refs.js +473 -0
- package/scripts/gds/local-preview-lib.js +159 -0
- package/scripts/gds/local-preview.js +95 -0
- package/scripts/gds/login.js +225 -0
- package/scripts/gds/main-audit.js +279 -0
- package/scripts/gds/me.js +88 -0
- package/scripts/gds/memory-map.js +174 -0
- package/scripts/gds/merge-lock.js +71 -0
- package/scripts/gds/migration-namespace.js +200 -0
- package/scripts/gds/mirror-lineage-check.js +319 -0
- package/scripts/gds/mirror-redact.js +305 -0
- package/scripts/gds/module.js +482 -0
- package/scripts/gds/newcomer-floor.config.json +13 -0
- package/scripts/gds/newcomer-floor.js +415 -0
- package/scripts/gds/newcomer-floor.templates.json +86 -0
- package/scripts/gds/newcomer-floor.test.js +235 -0
- package/scripts/gds/next-number.js +163 -0
- package/scripts/gds/oauth-secret.js +197 -0
- package/scripts/gds/onboard.js +217 -0
- package/scripts/gds/onboarding-analyze.js +226 -0
- package/scripts/gds/onboarding-config.js +178 -0
- package/scripts/gds/onboarding-ship.js +92 -0
- package/scripts/gds/package-core.js +684 -0
- package/scripts/gds/paste-token.js +131 -0
- package/scripts/gds/portability-smoke-art.sh +85 -0
- package/scripts/gds/portability-smoke-memory.sh +147 -0
- package/scripts/gds/provision.js +1324 -0
- package/scripts/gds/publish-manifest.js +307 -0
- package/scripts/gds/pulse.js +309 -0
- package/scripts/gds/push-main.js +45 -0
- package/scripts/gds/read-session-export.js +359 -0
- package/scripts/gds/reauth.js +149 -0
- package/scripts/gds/recall.js +135 -0
- package/scripts/gds/release.js +71 -0
- package/scripts/gds/render-ideas.js +173 -0
- package/scripts/gds/repo-metrics.js +363 -0
- package/scripts/gds/resolve-skill-model.js +57 -0
- package/scripts/gds/run-routine.js +197 -0
- package/scripts/gds/run-unit-tests.js +178 -0
- package/scripts/gds/sandbox-stage.js +653 -0
- package/scripts/gds/search-ingest-db.js +209 -0
- package/scripts/gds/search-ingest-md.js +225 -0
- package/scripts/gds/security-baseline-check.sh +180 -0
- package/scripts/gds/seed-adopt-tasks.js +75 -0
- package/scripts/gds/seed-api-contract-goal-tasks.js +141 -0
- package/scripts/gds/seed-bongos-app-tasks.js +294 -0
- package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +81 -0
- package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +100 -0
- package/scripts/gds/seed-bongos-goal-hierarchy-tasks.js +307 -0
- package/scripts/gds/seed-bongos-module-system-tasks.js +346 -0
- package/scripts/gds/seed-bongos-tasks.js +214 -0
- package/scripts/gds/seed-gds-v4-tasks.js +624 -0
- package/scripts/gds/seed-governance-tasks.js +340 -0
- package/scripts/gds/seed-medusa-tasks.js +440 -0
- package/scripts/gds/seed-module-upstreaming.js +219 -0
- package/scripts/gds/seed-productization-tasks.js +235 -0
- package/scripts/gds/seed-provisioning-tasks.js +83 -0
- package/scripts/gds/seed-staging.sh +104 -0
- package/scripts/gds/seed-v2-world-tasks.js +283 -0
- package/scripts/gds/seed-v3-tasks.js +1981 -0
- package/scripts/gds/session-cost.js +393 -0
- package/scripts/gds/session-digest.js +179 -0
- package/scripts/gds/session-eval.js +576 -0
- package/scripts/gds/session.js +404 -0
- package/scripts/gds/setup.js +504 -0
- package/scripts/gds/shell.js +100 -0
- package/scripts/gds/ship.js +3618 -0
- package/scripts/gds/smoke-batch-claim.sh +213 -0
- package/scripts/gds/smoke-batch-release.sh +296 -0
- package/scripts/gds/smoke-box.sh +150 -0
- package/scripts/gds/smoke-claim-consistency.sh +212 -0
- package/scripts/gds/smoke-dependencies.sh +84 -0
- package/scripts/gds/smoke-gds.js +125 -0
- package/scripts/gds/smoke-write.sh +168 -0
- package/scripts/gds/start.js +782 -0
- package/scripts/gds/status.js +365 -0
- package/scripts/gds/triage.js +366 -0
- package/scripts/gds/upgrade.js +421 -0
- package/scripts/gds/validate-design.js +254 -0
- package/scripts/gds/version-close.js +549 -0
- package/scripts/migrate.sh +183 -0
- package/scripts/migrate_cost_ledger.sh +178 -0
- package/scripts/public-mirror-export.js +291 -0
- package/scripts/render-diagrams.sh +88 -0
- package/scripts/security/dep-audit.js +276 -0
- package/scripts/setup-builder.js +274 -0
- package/scripts/setup-builder.sh +28 -0
- package/scripts/snapshots/backfill-history.mjs +292 -0
- package/scripts/snapshots/maybe-render-on-deploy.sh +66 -0
- package/scripts/snapshots/render-pre-art-eras.mjs +329 -0
- package/scripts/snapshots/render-world.mjs +322 -0
- package/scripts/status-mirror-sync.js +192 -0
- package/scripts/status-probe.mjs +185 -0
- package/server.js +212 -0
- package/src/asset-version.js +71 -0
- package/src/bongos/CLAUDE.md +64 -0
- package/src/bongos/api-errors.js +281 -0
- package/src/bongos/api-path-404.js +67 -0
- package/src/bongos/api-prefix.js +38 -0
- package/src/bongos/app-pair.js +172 -0
- package/src/bongos/auth.js +979 -0
- package/src/bongos/cascade-dispatch.js +123 -0
- package/src/bongos/db-kernel.js +252 -0
- package/src/bongos/db.js +911 -0
- package/src/bongos/goal-scope-check.js +120 -0
- package/src/bongos/hierarchy-config.js +189 -0
- package/src/bongos/live-channel.js +145 -0
- package/src/bongos/llm-cache.js +260 -0
- package/src/bongos/llm-pricing.js +220 -0
- package/src/bongos/metrics.js +286 -0
- package/src/bongos/middleware/audit.js +274 -0
- package/src/bongos/middleware/error-envelope.js +93 -0
- package/src/bongos/middleware/rate-limit.js +195 -0
- package/src/bongos/module-scope-map.js +271 -0
- package/src/bongos/optimizer.js +166 -0
- package/src/bongos/path-match.js +47 -0
- package/src/bongos/permission-path-check.js +248 -0
- package/src/bongos/pool.js +55 -0
- package/src/bongos/repo-info.js +91 -0
- package/src/bongos/route-rank-check.js +420 -0
- package/src/bongos/routes/CLAUDE.md +43 -0
- package/src/bongos/routes/_helpers.js +369 -0
- package/src/bongos/routes/audit-log.js +59 -0
- package/src/bongos/routes/auth.js +755 -0
- package/src/bongos/routes/backup.js +104 -0
- package/src/bongos/routes/builders.js +526 -0
- package/src/bongos/routes/healthz.js +16 -0
- package/src/bongos/routes/instance.js +129 -0
- package/src/bongos/routes/live.js +125 -0
- package/src/bongos/routes/llm-cache.js +119 -0
- package/src/bongos/routes/me.js +380 -0
- package/src/bongos/routes/modules.js +131 -0
- package/src/bongos/routes/optimizer.js +54 -0
- package/src/bongos/routes/public.js +476 -0
- package/src/bongos/routes/security.js +207 -0
- package/src/bongos/routes.js +166 -0
- package/src/bongos/secret-box.js +177 -0
- package/src/bongos/sensitive-surfaces.js +30 -0
- package/src/bongos/serve-internal.js +889 -0
- package/src/bongos/uptime-poller.js +90 -0
- package/src/bongos-downloads.js +70 -0
- package/src/branding.js +182 -0
- package/src/build-info.js +77 -0
- package/src/devbox-downloads.js +67 -0
- package/src/instance-config.js +200 -0
- package/src/module-api.js +366 -0
- package/src/module-loader/loader.js +268 -0
- package/src/module-loader/manifest-schema.js +140 -0
- package/src/module-loader/provenance.js +28 -0
- package/src/module-loader/semver.js +100 -0
- package/src/module-seams.js +291 -0
- package/src/modules.js +254 -0
- package/src/platform-server.js +135 -0
- package/src/ui/adapters/claude-design/index.js +333 -0
- package/src/ui/adapters/figma/index.js +328 -0
- package/tests/abandon_task.mjs +138 -0
- package/tests/achievements_reconcile.mjs +167 -0
- package/tests/adopt_detect.mjs +141 -0
- package/tests/adopt_import.mjs +132 -0
- package/tests/adopt_preflight.mjs +105 -0
- package/tests/anti_grid.mjs +89 -0
- package/tests/api_client.mjs +231 -0
- package/tests/api_docs.mjs +283 -0
- package/tests/api_error_envelope_buildcheck.mjs +56 -0
- package/tests/api_error_envelope_middleware.mjs +99 -0
- package/tests/api_error_registry.mjs +108 -0
- package/tests/api_pagination_contract.mjs +51 -0
- package/tests/api_path_404.mjs +96 -0
- package/tests/app_pair.mjs +168 -0
- package/tests/architect.mjs +140 -0
- package/tests/art_key.mjs +121 -0
- package/tests/art_stage.mjs +121 -0
- package/tests/asset_version.mjs +94 -0
- package/tests/atlas.mjs +69 -0
- package/tests/audit_deps.mjs +74 -0
- package/tests/audit_middleware.mjs +385 -0
- package/tests/auth_admission_gate.mjs +164 -0
- package/tests/auth_anthropic_identity.mjs +95 -0
- package/tests/auth_duplicate_cookie.mjs +56 -0
- package/tests/auth_error_brand.mjs +77 -0
- package/tests/auth_flow_slice1.mjs +223 -0
- package/tests/auth_inactive_builder.mjs +94 -0
- package/tests/auth_page_gate.mjs +92 -0
- package/tests/auth_session_ttl.mjs +155 -0
- package/tests/autonomous_fit_protected_paths.mjs +115 -0
- package/tests/autonomy_gate.mjs +85 -0
- package/tests/autotile_variants.mjs +256 -0
- package/tests/autotile_xverify.mjs +133 -0
- package/tests/backfill_sessions.mjs +101 -0
- package/tests/backfill_task_rewards.mjs +152 -0
- package/tests/backup_cli.mjs +104 -0
- package/tests/bfg.mjs +327 -0
- package/tests/bfg_write.mjs +423 -0
- package/tests/bongos_box_connect.mjs +89 -0
- package/tests/bongos_dispatch.mjs +74 -0
- package/tests/bongos_downloads.mjs +118 -0
- package/tests/bongos_login.mjs +34 -0
- package/tests/box_access.mjs +186 -0
- package/tests/box_auth_check.mjs +114 -0
- package/tests/box_code_staleness.mjs +116 -0
- package/tests/box_connect_e2e.mjs +196 -0
- package/tests/box_cost.mjs +70 -0
- package/tests/box_dns_repoint.mjs +151 -0
- package/tests/box_host_keys.mjs +102 -0
- package/tests/box_onboard.mjs +317 -0
- package/tests/box_scope_session.mjs +115 -0
- package/tests/box_ship_permissions.mjs +71 -0
- package/tests/box_terminal_ssrf.mjs +90 -0
- package/tests/boxes.mjs +1255 -0
- package/tests/branding.mjs +88 -0
- package/tests/bug_attachments.mjs +189 -0
- package/tests/build_info.mjs +88 -0
- package/tests/builder_needs.mjs +99 -0
- package/tests/cap_newcomer_tasks.mjs +114 -0
- package/tests/cascade-dispatch.mjs +95 -0
- package/tests/cf_tunnel.mjs +459 -0
- package/tests/claim_recall.mjs +150 -0
- package/tests/claims_bind_session.mjs +47 -0
- package/tests/claude_materialize.mjs +148 -0
- package/tests/cli_box_scope.mjs +52 -0
- package/tests/cli_lib_formatters.mjs +87 -0
- package/tests/cli_token_reissue.mjs +147 -0
- package/tests/client_bundle_route.mjs +47 -0
- package/tests/cloud_bongos_pack.mjs +85 -0
- package/tests/conductor.mjs +496 -0
- package/tests/confirm_attribution.mjs +156 -0
- package/tests/conflict_resolve.mjs +462 -0
- package/tests/context_pack.mjs +240 -0
- package/tests/cost.mjs +94 -0
- package/tests/cost_audit.mjs +122 -0
- package/tests/cost_budget_status.mjs +78 -0
- package/tests/cost_reconcile.mjs +102 -0
- package/tests/cost_summary_shape.mjs +94 -0
- package/tests/credit_grant.mjs +376 -0
- package/tests/criterion_progress.mjs +220 -0
- package/tests/criterion_proposal.mjs +109 -0
- package/tests/criterion_ref_parse.mjs +53 -0
- package/tests/currency_label.mjs +119 -0
- package/tests/day_cycle.mjs +197 -0
- package/tests/dependencies_migration.mjs +77 -0
- package/tests/dependencies_polymorphic.mjs +212 -0
- package/tests/deploy_instance.mjs +78 -0
- package/tests/devbox_downloads.mjs +122 -0
- package/tests/diff_derived_signals.mjs +115 -0
- package/tests/discord_approvals.mjs +174 -0
- package/tests/discord_autojoin.mjs +158 -0
- package/tests/discord_bot.mjs +94 -0
- package/tests/discord_bugs.mjs +297 -0
- package/tests/discord_channels.mjs +337 -0
- package/tests/discord_foundation.mjs +76 -0
- package/tests/discord_inbound.mjs +190 -0
- package/tests/discord_message_buffer.mjs +87 -0
- package/tests/discord_oauth.mjs +55 -0
- package/tests/discord_reaction.mjs +170 -0
- package/tests/discord_role_sync.mjs +151 -0
- package/tests/display_name.mjs +123 -0
- package/tests/dns_preflight.mjs +74 -0
- package/tests/event_sound_prefs.mjs +194 -0
- package/tests/eviction_policy.mjs +279 -0
- package/tests/figma_adapter.mjs +199 -0
- package/tests/file_map.mjs +91 -0
- package/tests/first_admin_bootstrap.mjs +40 -0
- package/tests/fitness.mjs +435 -0
- package/tests/fitness_two_root.mjs +104 -0
- package/tests/fixtures/session-506-digest.json +34 -0
- package/tests/gate_approvals.mjs +451 -0
- package/tests/gate_review.mjs +152 -0
- package/tests/git_merge_regen.mjs +151 -0
- package/tests/github_push_ancestry.mjs +119 -0
- package/tests/github_push_land_proof.mjs +127 -0
- package/tests/github_push_merge_driver.mjs +175 -0
- package/tests/goal_abuse_matrix.mjs +187 -0
- package/tests/goal_achievement.mjs +146 -0
- package/tests/goal_conflicts.mjs +305 -0
- package/tests/goal_dependencies_read.mjs +73 -0
- package/tests/goal_member_roles.mjs +420 -0
- package/tests/goal_membership_requests.mjs +332 -0
- package/tests/goal_routes.mjs +203 -0
- package/tests/goal_scope_check.mjs +167 -0
- package/tests/goal_tier.mjs +312 -0
- package/tests/goal_wall_proof.mjs +112 -0
- package/tests/grade_attempts.mjs +73 -0
- package/tests/grade_attribution.mjs +117 -0
- package/tests/grade_diff_hash.mjs +191 -0
- package/tests/grade_server_authoritative.mjs +305 -0
- package/tests/grade_unavailable_display.mjs +66 -0
- package/tests/grader.mjs +1960 -0
- package/tests/grader_bypass.mjs +57 -0
- package/tests/grader_panel.mjs +252 -0
- package/tests/grader_prompt_fencing.mjs +192 -0
- package/tests/helpers.mjs +52 -0
- package/tests/hierarchy-config.mjs +81 -0
- package/tests/init.mjs +463 -0
- package/tests/instance_config.mjs +76 -0
- package/tests/instance_manifest.mjs +110 -0
- package/tests/interaction_prefs.mjs +72 -0
- package/tests/key-card.mjs +110 -0
- package/tests/key-status.mjs +45 -0
- package/tests/land_watch.mjs +115 -0
- package/tests/lifecycle-card.mjs +145 -0
- package/tests/lifecycle_breakdown_view.mjs +236 -0
- package/tests/linkify_refs.mjs +264 -0
- package/tests/live_channel.mjs +128 -0
- package/tests/live_sse.mjs +122 -0
- package/tests/llm-cache-route.mjs +110 -0
- package/tests/llm-cache.mjs +140 -0
- package/tests/llm-pricing.mjs +152 -0
- package/tests/local_preview.mjs +136 -0
- package/tests/main_audit.mjs +137 -0
- package/tests/memory_isolation.mjs +431 -0
- package/tests/memory_map.mjs +107 -0
- package/tests/memory_pull.mjs +429 -0
- package/tests/merge_lease.mjs +100 -0
- package/tests/merge_lock.mjs +312 -0
- package/tests/metrics.mjs +147 -0
- package/tests/migration_allocation.mjs +146 -0
- package/tests/migration_namespace.mjs +185 -0
- package/tests/migrations_fresh_replay_guard.mjs +38 -0
- package/tests/mirror_lineage_fulltree.mjs +45 -0
- package/tests/mirror_lineage_proof.mjs +72 -0
- package/tests/mirror_redact.mjs +193 -0
- package/tests/model_alloc_prefs.mjs +63 -0
- package/tests/module-scope-map.mjs +88 -0
- package/tests/module_api.mjs +110 -0
- package/tests/module_cli.mjs +292 -0
- package/tests/module_contributions.mjs +148 -0
- package/tests/module_loader.mjs +286 -0
- package/tests/module_manifest.mjs +194 -0
- package/tests/module_owned_tests.mjs +105 -0
- package/tests/module_provenance.mjs +34 -0
- package/tests/module_route_rank.mjs +147 -0
- package/tests/module_seams.mjs +68 -0
- package/tests/modules.mjs +156 -0
- package/tests/modules_route.mjs +38 -0
- package/tests/newcomer_floor.mjs +17 -0
- package/tests/newcomer_restock.mjs +80 -0
- package/tests/next_number.mjs +154 -0
- package/tests/oauth_secret.mjs +60 -0
- package/tests/onboard.mjs +70 -0
- package/tests/onboarding_gate.mjs +267 -0
- package/tests/onboarding_observability.mjs +344 -0
- package/tests/onboarding_route_signals.mjs +175 -0
- package/tests/onboarding_state.mjs +346 -0
- package/tests/one_active_claim_per_session.mjs +111 -0
- package/tests/orphaned_claim_ship.mjs +135 -0
- package/tests/override_attribution.mjs +142 -0
- package/tests/override_request_ownership.mjs +235 -0
- package/tests/package_core.mjs +435 -0
- package/tests/parallel-load.mjs +402 -0
- package/tests/path_match.mjs +62 -0
- package/tests/permission_path.mjs +151 -0
- package/tests/platform_boot.mjs +167 -0
- package/tests/pre_compact.mjs +60 -0
- package/tests/preview_server.mjs +127 -0
- package/tests/profile_route.mjs +197 -0
- package/tests/provision.mjs +805 -0
- package/tests/provisioning_github_app_routes.mjs +98 -0
- package/tests/public_mirror_export.mjs +124 -0
- package/tests/public_task_resolver.mjs +112 -0
- package/tests/publish_branch_route.mjs +422 -0
- package/tests/publish_manifest.mjs +184 -0
- package/tests/publish_reconciler.mjs +728 -0
- package/tests/rank_gate.mjs +463 -0
- package/tests/rate_limit_public.mjs +217 -0
- package/tests/read_session_export.mjs +89 -0
- package/tests/recall_cli.mjs +82 -0
- package/tests/recall_hints.mjs +119 -0
- package/tests/recent_shipped_window.mjs +80 -0
- package/tests/regrade_eligibility.mjs +202 -0
- package/tests/render_prefs.mjs +122 -0
- package/tests/repo_map.mjs +92 -0
- package/tests/reward_gate.mjs +284 -0
- package/tests/route_rank_check.mjs +243 -0
- package/tests/route_validation.mjs +490 -0
- package/tests/routine_timers.mjs +72 -0
- package/tests/rubric_fixtures.mjs +140 -0
- package/tests/run_routine.mjs +69 -0
- package/tests/sandbox_stage.mjs +582 -0
- package/tests/scrubber_corpus.mjs +257 -0
- package/tests/search_chunker.mjs +209 -0
- package/tests/search_ingest.mjs +96 -0
- package/tests/search_ingest_db.mjs +88 -0
- package/tests/search_isolation.mjs +204 -0
- package/tests/search_route.mjs +95 -0
- package/tests/secret_box.mjs +189 -0
- package/tests/security_docs.mjs +186 -0
- package/tests/security_route.mjs +108 -0
- package/tests/served_paths_shipped.mjs +118 -0
- package/tests/session-cards.mjs +142 -0
- package/tests/session_506_regression.mjs +69 -0
- package/tests/session_caps.mjs +238 -0
- package/tests/session_cost.mjs +133 -0
- package/tests/session_digest.mjs +73 -0
- package/tests/session_eval.mjs +386 -0
- package/tests/session_index.mjs +105 -0
- package/tests/session_records.mjs +369 -0
- package/tests/session_search.mjs +78 -0
- package/tests/session_start_freshness.mjs +123 -0
- package/tests/setup_smoke.mjs +154 -0
- package/tests/ship_autolinkify.mjs +60 -0
- package/tests/ship_automerge_injection.mjs +174 -0
- package/tests/ship_broadcast_routing.mjs +125 -0
- package/tests/ship_broadcast_server.mjs +175 -0
- package/tests/ship_card.mjs +280 -0
- package/tests/ship_ci_deploy.mjs +374 -0
- package/tests/ship_preflight.mjs +368 -0
- package/tests/ship_premerge.mjs +75 -0
- package/tests/ship_resume.mjs +129 -0
- package/tests/ship_upload_skip.mjs +89 -0
- package/tests/ship_zero_commit.mjs +60 -0
- package/tests/single_host_hall.mjs +98 -0
- package/tests/skill_prefs.mjs +150 -0
- package/tests/smoke_preflight.mjs +66 -0
- package/tests/snapshot_picker.mjs +233 -0
- package/tests/sound_prefs.mjs +198 -0
- package/tests/sprite_facing.mjs +35 -0
- package/tests/status-probe.mjs +89 -0
- package/tests/status_backfill.mjs +94 -0
- package/tests/stop_refcheck.mjs +127 -0
- package/tests/streak.mjs +175 -0
- package/tests/subdomain_auth.mjs +58 -0
- package/tests/task_classifier_vocab.mjs +41 -0
- package/tests/task_create_idempotency.mjs +96 -0
- package/tests/task_goal_link.mjs +93 -0
- package/tests/task_ownership_gate.mjs +125 -0
- package/tests/terrain_picker.mjs +298 -0
- package/tests/touches_overlap.mjs +75 -0
- package/tests/triage_development.mjs +140 -0
- package/tests/turn_in_place.mjs +280 -0
- package/tests/upgrade.mjs +357 -0
- package/tests/verify_task_guard.mjs +64 -0
- package/tests/version_close.mjs +76 -0
- package/tests/versions_route.mjs +93 -0
- package/tests/walkability.mjs +188 -0
- package/tests/wandering_prefs.mjs +176 -0
- package/tests/worktree_disambiguation.mjs +105 -0
- package/tests/worktree_guard.mjs +90 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// src/bongos/routes/security.js — security-the-PROPERTY surfaces (kernel side).
|
|
2
|
+
//
|
|
3
|
+
// What stays here (02-module-map §5 — security-the-PROPERTY, NOT the feature):
|
|
4
|
+
// • GET /security/adr — the full security ADR (Metic+), read off the droplet.
|
|
5
|
+
// • GET/POST /security/docs — the Archon-only exploit-detail engagement-report
|
|
6
|
+
// store (backed by the core db.js security_docs queries, task 991).
|
|
7
|
+
//
|
|
8
|
+
// The FEATURE half — the red-team / vulnerability reports + bounty intake &
|
|
9
|
+
// adjudication (V3.R63-R66 / #282-285) — carved out to modules/security/ in
|
|
10
|
+
// BV1.R79 (ADR 0093 §1); the loader mounts modules/security/routes/reports.js,
|
|
11
|
+
// and core's /public/bounty-table resolves the `security` kernel port it
|
|
12
|
+
// registers (no core require of the module).
|
|
13
|
+
//
|
|
14
|
+
// The public ADR stub lives in docs/adr/0020-security-model-public-stub.md; the
|
|
15
|
+
// *real* document lives at the path named by env GDS_SECURITY_ADR_PATH on the
|
|
16
|
+
// droplet (NOT in the repo) so the most attacker-useful document doesn't get
|
|
17
|
+
// committed to a public surface. See ADR 0020 for the reasoning.
|
|
18
|
+
|
|
19
|
+
const express = require('express');
|
|
20
|
+
const fs = require('node:fs/promises');
|
|
21
|
+
const auth = require('../auth');
|
|
22
|
+
const db = require('../db');
|
|
23
|
+
const { validateOrRespond } = require('./_helpers');
|
|
24
|
+
|
|
25
|
+
// Slug shape for security_docs (task 991): lowercase kebab, 1–128 chars. Used to
|
|
26
|
+
// validate POST /security/docs and to safely interpolate :slug into the GET.
|
|
27
|
+
const SECURITY_DOC_SLUG_RE = /^[a-z0-9-]{1,128}$/;
|
|
28
|
+
|
|
29
|
+
// content_md is a full-report store, NOT a task/report field — so it gets its
|
|
30
|
+
// own explicit large cap, deliberately well above LIMITS.DESCRIPTION (50k). A
|
|
31
|
+
// dated engagement report runs tens of KB; 2 MB leaves generous headroom while
|
|
32
|
+
// still bounding a runaway upload.
|
|
33
|
+
const SECURITY_DOC_CONTENT_MAX = 2_000_000;
|
|
34
|
+
|
|
35
|
+
// Where the full ADR is expected to live on the droplet. Configurable so dev /
|
|
36
|
+
// staging can point at a different file; the recommended prod path is
|
|
37
|
+
// /etc/amazonprimea/security-adr.md (chmod 600, owned by the deploy user).
|
|
38
|
+
function adrPath() {
|
|
39
|
+
return (process.env.GDS_SECURITY_ADR_PATH || '').trim() || null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Read the full ADR off disk. Returns { adr_md, source, fetched_at } on
|
|
43
|
+
// success, or null if the env var isn't set or the file isn't readable.
|
|
44
|
+
// Errors are swallowed (and console.error'd) — a missing/unreadable file
|
|
45
|
+
// surfaces to the caller as a 404, not a 500, because file-not-found is the
|
|
46
|
+
// expected unprovisioned state, not an internal failure. We DO distinguish
|
|
47
|
+
// "env not set" (configuration bug) from "file unreadable" (probably perms /
|
|
48
|
+
// not yet provisioned) in the hint string returned to the caller.
|
|
49
|
+
async function readFullAdr() {
|
|
50
|
+
const p = adrPath();
|
|
51
|
+
if (!p) {
|
|
52
|
+
return { ok: false, reason: 'env_not_set' };
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const buf = await fs.readFile(p, 'utf8');
|
|
56
|
+
return {
|
|
57
|
+
ok: true,
|
|
58
|
+
payload: {
|
|
59
|
+
adr_md: buf,
|
|
60
|
+
source: p,
|
|
61
|
+
fetched_at: new Date().toISOString(),
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
} catch (err) {
|
|
65
|
+
// Treat ENOENT, EACCES, etc. uniformly — the caller (Metic+) doesn't need
|
|
66
|
+
// to debug the droplet's filesystem from the API response. Log details
|
|
67
|
+
// server-side for the operator.
|
|
68
|
+
console.error('[gds] /security/adr read failed:', err.code || err.message);
|
|
69
|
+
return { ok: false, reason: 'file_unreadable', code: err.code || null };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = function buildSecurityRouter() {
|
|
74
|
+
const router = express.Router();
|
|
75
|
+
|
|
76
|
+
// GET /api/gds/security/adr
|
|
77
|
+
//
|
|
78
|
+
// Metic+ only. Returns the full security ADR as { adr_md, source,
|
|
79
|
+
// fetched_at } when the file is provisioned; otherwise 404 with a
|
|
80
|
+
// structured hint. The rank gate runs BEFORE the file-existence check so a
|
|
81
|
+
// Xenos sees 403 regardless of whether the document is provisioned — we
|
|
82
|
+
// don't want existence-or-not to leak below the rank line.
|
|
83
|
+
//
|
|
84
|
+
// rank: metic+archon — trust-tier access to the threat model + defenses
|
|
85
|
+
// inventory (ADR 0020).
|
|
86
|
+
router.get(
|
|
87
|
+
'/security/adr',
|
|
88
|
+
auth.requireBuilder,
|
|
89
|
+
auth.requireRank('metic', 'archon'),
|
|
90
|
+
async (_req, res) => {
|
|
91
|
+
const result = await readFullAdr();
|
|
92
|
+
if (result.ok) {
|
|
93
|
+
// No caching — the full ADR is the live document; treating it as
|
|
94
|
+
// cacheable would invite a stale-defense problem after a defense
|
|
95
|
+
// update. Cost is trivial (one disk read per Metic request).
|
|
96
|
+
res.set('Cache-Control', 'no-store');
|
|
97
|
+
return res.json(result.payload);
|
|
98
|
+
}
|
|
99
|
+
const hint =
|
|
100
|
+
result.reason === 'env_not_set'
|
|
101
|
+
? 'GDS_SECURITY_ADR_PATH is unset on the server; an Archon must provision the file and the env var.'
|
|
102
|
+
: 'GDS_SECURITY_ADR_PATH is set but the file is unreadable (missing, wrong perms, or wrong path).';
|
|
103
|
+
return res.fail('security_adr_not_provisioned', 404, { reason: result.reason, hint });
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// -----------------------------------------------------------------------
|
|
108
|
+
// Security engagement docs — Archon-only document store (task 991).
|
|
109
|
+
//
|
|
110
|
+
// The DATED security engagement reports (exploit detail — full repro,
|
|
111
|
+
// evidence, the attacker cookbook) are served from the DB, NOT committed to
|
|
112
|
+
// the git clone: the repo is cloned in full onto every Metic+ dev box
|
|
113
|
+
// (threat-model §6.3 / ADR 0020), so a committed exploit report is an
|
|
114
|
+
// attacker cookbook on every box. The SAFE conceptual docs (threat-model.md,
|
|
115
|
+
// the README) stay in docs/security/; only the dated reports live here, and
|
|
116
|
+
// ALL three routes are requireRank('archon') because they serve exploit
|
|
117
|
+
// detail. Content is uploaded by the director via the POST route after
|
|
118
|
+
// deploy — no exploit content ever touches the repo.
|
|
119
|
+
// -----------------------------------------------------------------------
|
|
120
|
+
|
|
121
|
+
// GET /api/gds/security/docs — list doc METADATA (no content).
|
|
122
|
+
//
|
|
123
|
+
// rank: archon — index of exploit-detail engagement reports.
|
|
124
|
+
router.get('/security/docs',
|
|
125
|
+
auth.requireBuilder,
|
|
126
|
+
auth.requireRank('archon'),
|
|
127
|
+
async (_req, res) => {
|
|
128
|
+
try {
|
|
129
|
+
const docs = await db.listSecurityDocs();
|
|
130
|
+
res.set('Cache-Control', 'no-store');
|
|
131
|
+
res.json({ docs });
|
|
132
|
+
} catch (err) {
|
|
133
|
+
console.error('[gds] GET /security/docs', err);
|
|
134
|
+
res.fail('list_failed', { status: 500, message: 'internal error' });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
// GET /api/gds/security/docs/:slug — one doc WITH content, or 404.
|
|
140
|
+
//
|
|
141
|
+
// rank: archon — reads the full exploit-detail report body.
|
|
142
|
+
router.get('/security/docs/:slug',
|
|
143
|
+
auth.requireBuilder,
|
|
144
|
+
auth.requireRank('archon'),
|
|
145
|
+
async (req, res) => {
|
|
146
|
+
const slug = String(req.params.slug || '');
|
|
147
|
+
if (!SECURITY_DOC_SLUG_RE.test(slug)) {
|
|
148
|
+
return res.fail('bad_slug', 400, { pattern: SECURITY_DOC_SLUG_RE.source });
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const doc = await db.getSecurityDoc(slug);
|
|
152
|
+
if (!doc) {
|
|
153
|
+
return res.fail('security_doc_not_found', 404, { slug });
|
|
154
|
+
}
|
|
155
|
+
res.set('Cache-Control', 'no-store');
|
|
156
|
+
res.json({
|
|
157
|
+
doc: {
|
|
158
|
+
slug: doc.slug,
|
|
159
|
+
title: doc.title,
|
|
160
|
+
content_md: doc.content_md,
|
|
161
|
+
updated_at: doc.updated_at,
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
} catch (err) {
|
|
165
|
+
console.error('[gds] GET /security/docs/:slug', err);
|
|
166
|
+
res.fail('get_failed', { status: 500, message: 'internal error' });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// POST /api/gds/security/docs — upsert a doc by slug. The director uploads
|
|
172
|
+
// each dated engagement report here after deploy.
|
|
173
|
+
//
|
|
174
|
+
// Body: { slug, title, content_md }. content_md uses a large explicit cap
|
|
175
|
+
// (full reports), NOT the small LIMITS.DESCRIPTION. Returns 201 + the row.
|
|
176
|
+
//
|
|
177
|
+
// rank: archon — writes exploit-detail report bodies.
|
|
178
|
+
router.post('/security/docs',
|
|
179
|
+
auth.requireBuilder,
|
|
180
|
+
auth.requireRank('archon'),
|
|
181
|
+
async (req, res) => {
|
|
182
|
+
if (validateOrRespond(req, res, {
|
|
183
|
+
slug: { required: true, type: 'string', maxLength: 128, minLength: 1 },
|
|
184
|
+
title: { required: true, type: 'string', maxLength: 200, minLength: 1 },
|
|
185
|
+
content_md: { required: true, type: 'string', maxLength: SECURITY_DOC_CONTENT_MAX, minLength: 1 },
|
|
186
|
+
})) return;
|
|
187
|
+
const { slug, title, content_md: contentMd } = req.body || {};
|
|
188
|
+
// Slug needs the exact kebab shape on top of the length check — the
|
|
189
|
+
// length-only validator above can't express the character class.
|
|
190
|
+
if (!SECURITY_DOC_SLUG_RE.test(slug)) {
|
|
191
|
+
return res.fail('bad_slug', 400, { pattern: SECURITY_DOC_SLUG_RE.source });
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
const row = await db.upsertSecurityDoc({ slug, title, contentMd });
|
|
195
|
+
res.status(201).json({ ok: true, doc: row });
|
|
196
|
+
} catch (err) {
|
|
197
|
+
console.error('[gds] POST /security/docs', err);
|
|
198
|
+
res.fail('upsert_failed', { status: 500, message: 'internal error' });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
return router;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// Exposed for the test suite — pure helpers, no router state.
|
|
207
|
+
module.exports._internals = { adrPath, readFullAdr };
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// GDS HTTP routes — mounted at /api/bongos (canonical) + /api/gds (permanent
|
|
2
|
+
// alias); serve-internal.js dual-mounts this router at both (src/bongos/api-prefix.js).
|
|
3
|
+
// Historical: the older /api/pms surface was removed in V3.R01-followup (#308) — it
|
|
4
|
+
// now 404s (not a redirect).
|
|
5
|
+
//
|
|
6
|
+
// This file is a thin mounter. Each feature owns its own sub-router under
|
|
7
|
+
// src/bongos/routes/. Adding a new feature = create one new file there + add one
|
|
8
|
+
// line below. That's the whole point: keep routes.js conflict-free across
|
|
9
|
+
// parallel branches.
|
|
10
|
+
//
|
|
11
|
+
// Three logical groups:
|
|
12
|
+
// - /auth/* — GitHub Device Flow (CLI) + Authorization Code (web)
|
|
13
|
+
// - /me, /tasks/*, /claims/*, /cost/*, /credits/*, ... — authenticated CLI/web ops
|
|
14
|
+
// - /public/* — read-only, no auth, for status.amazonprimea.com
|
|
15
|
+
//
|
|
16
|
+
// All JSON. Same Express app as the game server.
|
|
17
|
+
|
|
18
|
+
const express = require('express');
|
|
19
|
+
|
|
20
|
+
const buildHealthzRouter = require('./routes/healthz');
|
|
21
|
+
const buildInstanceRouter = require('./routes/instance');
|
|
22
|
+
const buildAuthRouter = require('./routes/auth');
|
|
23
|
+
const buildMeRouter = require('./routes/me');
|
|
24
|
+
const buildBuildersRouter = require('./routes/builders');
|
|
25
|
+
// The LIFECYCLE routes (tasks · claims · versions · done-when · goals ·
|
|
26
|
+
// dependencies · gate-approvals · analytics) carved into modules/lifecycle/
|
|
27
|
+
// (BV1.R86 / ADR 0093 §1,§3); moduleLoader.mountModuleRoutes (below) mounts them
|
|
28
|
+
// via the lifecycle module's route factories — no core require. The `/tasks/:id/
|
|
29
|
+
// publish-branch` body-parser bypass below STAYS (the route carries its own larger
|
|
30
|
+
// express.json, exactly like memory's /memory/sync — the moved route mounts AFTER
|
|
31
|
+
// the global parser middleware runs, so the by-path skip still fires).
|
|
32
|
+
// cost + leaderboard routes carved into modules/economy/ (BV1.R77 / ADR 0093
|
|
33
|
+
// §1-2); moduleLoader.mountModuleRoutes (below) mounts them now — no core require.
|
|
34
|
+
// autonomy precheck route carved into modules/autonomy/ (BV1.R83 / ADR 0093 §1);
|
|
35
|
+
// moduleLoader.mountModuleRoutes (below) mounts it now — no core require.
|
|
36
|
+
// inbox + blockers routes carved into modules/ideas/ (BV1.R78 / ADR 0093 §1);
|
|
37
|
+
// memory/search/learnings routes carved into modules/memory/ (BV1.R72 / ADR 0091
|
|
38
|
+
// §2); moduleLoader.mountModuleRoutes (below) mounts both now — no core require.
|
|
39
|
+
const buildOptimizerRouter = require('./routes/optimizer');
|
|
40
|
+
const buildBackupRouter = require('./routes/backup');
|
|
41
|
+
const buildPublicRouter = require('./routes/public');
|
|
42
|
+
const buildAuditLogRouter = require('./routes/audit-log');
|
|
43
|
+
// security router: now the PROPERTY half only (/security/adr + /security/docs).
|
|
44
|
+
// The red-team-reports + bounty FEATURE carved to modules/security/ (BV1.R79 /
|
|
45
|
+
// ADR 0093 §1); moduleLoader.mountModuleRoutes (below) mounts those — no core
|
|
46
|
+
// require. (02-module-map §5: security-the-property stays kernel.)
|
|
47
|
+
const buildSecurityRouter = require('./routes/security');
|
|
48
|
+
// The hall "Modules" tab (ADR 0107 §9, task 1776) — list/enable/disable +
|
|
49
|
+
// the submit-for-review front door. Core (not module-owned): it manages
|
|
50
|
+
// EVERY module's enablement, including modules it must not import.
|
|
51
|
+
const buildModulesRouter = require('./routes/modules');
|
|
52
|
+
// The access-request ADMISSION routes carved to modules/onboarding/ (BV1.R81 /
|
|
53
|
+
// ADR 0093 §1); moduleLoader.mountModuleRoutes (below) mounts them via the
|
|
54
|
+
// onboarding module's route factory — no core require.
|
|
55
|
+
// The session-records data plane (POST /sessions + the BFG search/deep-dive)
|
|
56
|
+
// carved to modules/sessions/ (BV1.R82 / ADR 0093 §1); moduleLoader.mountModuleRoutes
|
|
57
|
+
// (below) mounts it via the sessions module's route factory — no core require.
|
|
58
|
+
// The `/sessions` global-parser bypass below STAYS (the module router carries
|
|
59
|
+
// its own larger express.json, exactly like memory's /memory/sync).
|
|
60
|
+
const buildLiveRouter = require('./routes/live');
|
|
61
|
+
const buildLlmCacheRouter = require('./routes/llm-cache');
|
|
62
|
+
const { isModuleEnabled } = require('../modules');
|
|
63
|
+
const moduleLoader = require('../module-loader/loader');
|
|
64
|
+
const { auditMiddleware } = require('./middleware/audit');
|
|
65
|
+
const { rateLimitMiddleware } = require('./middleware/rate-limit');
|
|
66
|
+
const { attachFail, errorEnvelopeHandler } = require('./middleware/error-envelope');
|
|
67
|
+
|
|
68
|
+
function buildGdsRouter() {
|
|
69
|
+
const router = express.Router();
|
|
70
|
+
// Global JSON body parser, 64 KB — the right cap for every GDS write EXCEPT
|
|
71
|
+
// memory sync (#274), whose body batches up to 1 MB markdown files. We skip
|
|
72
|
+
// that one path here so the memory router's own larger express.json (in
|
|
73
|
+
// routes/memory.js) is the only parser that runs for it; every other route
|
|
74
|
+
// keeps the tight 64 KB cap. Without this skip the global parser would 413
|
|
75
|
+
// a large memory-sync body before the route-scoped parser could see it.
|
|
76
|
+
const globalJson = express.json({ limit: '64kb' });
|
|
77
|
+
router.use((req, res, next) => {
|
|
78
|
+
// These paths carry larger bodies (memory markdown batches; session digests
|
|
79
|
+
// — 6D.1 / ADR 0027; server-mediated branch publish bundles — ADR 0055) and
|
|
80
|
+
// mount their OWN express.json in their routers. Skip the tight global cap so
|
|
81
|
+
// it doesn't 413 the body before the route parser runs. The publish path
|
|
82
|
+
// carries a dynamic :id, so it's matched by pattern, not equality.
|
|
83
|
+
if (
|
|
84
|
+
req.path === '/memory/sync' ||
|
|
85
|
+
req.path === '/sessions' ||
|
|
86
|
+
req.path === '/llm-cache/store' ||
|
|
87
|
+
/^\/tasks\/\d+\/publish-branch$/.test(req.path)
|
|
88
|
+
) return next();
|
|
89
|
+
return globalJson(req, res, next);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Audit middleware (V3.R35 #256) — attaches a res 'finish' hook so every
|
|
93
|
+
// authenticated POST/PATCH/PUT/DELETE under /api/gds is recorded in
|
|
94
|
+
// audit_log AFTER the response is sent. It cannot fail the request: throws
|
|
95
|
+
// are caught, DB errors are swallowed, and it never mutates req/res in a
|
|
96
|
+
// way downstream handlers can see. Mounted BEFORE the feature routers so
|
|
97
|
+
// the hook is attached early; the actual write fires only on 'finish'.
|
|
98
|
+
//
|
|
99
|
+
// Order matters: audit runs first (attaches the finish hook), then rate-
|
|
100
|
+
// limit decides allow/deny. A 429 still fires the audit hook on 'finish',
|
|
101
|
+
// so the forensic record of throttled attempts is intact (pairs with R36).
|
|
102
|
+
// Error-envelope decorator (BV1 R02 / task 1989 / ADR 0116) — hangs
|
|
103
|
+
// res.fail(code, status?, details?) on every response so handlers emit the
|
|
104
|
+
// one canonical envelope. Mounted before the feature routers so all of them
|
|
105
|
+
// (and the trailing error handler) can rely on it. Adds a method; touches no
|
|
106
|
+
// existing response — the R04 sweep migrates handlers onto it incrementally.
|
|
107
|
+
router.use(attachFail);
|
|
108
|
+
|
|
109
|
+
router.use(auditMiddleware());
|
|
110
|
+
|
|
111
|
+
// Rate-limit middleware (V3.R34 #255) — sliding-window in-memory limiter.
|
|
112
|
+
// 30 writes/min per IP, 60 writes/min per session. Reads uncapped.
|
|
113
|
+
// 429 + Retry-After + X-RateLimit-* headers on trip.
|
|
114
|
+
router.use(rateLimitMiddleware);
|
|
115
|
+
|
|
116
|
+
router.use(buildHealthzRouter());
|
|
117
|
+
router.use(buildInstanceRouter());
|
|
118
|
+
router.use(buildAuthRouter());
|
|
119
|
+
router.use(buildMeRouter());
|
|
120
|
+
router.use(buildBuildersRouter());
|
|
121
|
+
// tasks · claims · versions · done-when · goals · dependencies · analytics now
|
|
122
|
+
// mount via moduleLoader.mountModuleRoutes below (lifecycle module, BV1.R86) —
|
|
123
|
+
// BEFORE the public router, so their paths are byte-identical.
|
|
124
|
+
router.use(buildOptimizerRouter());
|
|
125
|
+
router.use(buildBackupRouter());
|
|
126
|
+
router.use(buildAuditLogRouter());
|
|
127
|
+
router.use(buildSecurityRouter());
|
|
128
|
+
router.use(buildModulesRouter());
|
|
129
|
+
// access-requests (admission) is now mounted by the onboarding module via
|
|
130
|
+
// moduleLoader.mountModuleRoutes below (BV1.R81) — still BEFORE the public
|
|
131
|
+
// router, so its paths are byte-identical. The /sessions data plane is
|
|
132
|
+
// likewise mounted by the sessions module (BV1.R82) via mountModuleRoutes.
|
|
133
|
+
// R55 (task 1194 / ADR 0069): the hall's live-update SSE channel. Mounted
|
|
134
|
+
// UNCONDITIONALLY (not module-gated) — it replaces the Colyseus builders_hall
|
|
135
|
+
// room so the hall refreshes live on a game-less Cloud Bongos boot, which is
|
|
136
|
+
// core to every instance, not an OTB feature.
|
|
137
|
+
router.use(buildLiveRouter());
|
|
138
|
+
// Feature-module-gated mounts (R54, task 1193, ADR 0062 §4). Off on a vanilla
|
|
139
|
+
// instance; ON for OTB via config/modules.json so prod is unchanged. dev-box,
|
|
140
|
+
// art-pipeline, and discord (with its bug-attachments route) have all graduated
|
|
141
|
+
// into real modules (modules/<key>/) — they are discovered + mounted by
|
|
142
|
+
// moduleLoader.mountModuleRoutes below, not here (BV1.R43 / R48 / R47 / R72).
|
|
143
|
+
// gate-approvals likewise moved to the lifecycle module (BV1.R86).
|
|
144
|
+
router.use(buildLlmCacheRouter());
|
|
145
|
+
|
|
146
|
+
// Loader-mounted module routers (ADR 0083 / BV1.R41). Discovers + mounts every
|
|
147
|
+
// ENABLED module under modules/*/ behind the kernel's audit + rate-limit (already
|
|
148
|
+
// applied above); each module's route factory self-gates per route (enforced by
|
|
149
|
+
// the route-rank fitness check, BV1.R44). No-op until a module is moved into
|
|
150
|
+
// modules/ — so OTB is byte-identical today. Mounted BEFORE the public router so
|
|
151
|
+
// the public catch-all prefixes can't shadow a module's routes.
|
|
152
|
+
moduleLoader.mountModuleRoutes(router, { isEnabled: isModuleEnabled });
|
|
153
|
+
|
|
154
|
+
router.use(buildPublicRouter());
|
|
155
|
+
|
|
156
|
+
// Central error handler (BV1 R02 / task 1989 / ADR 0116) — MUST be last, after
|
|
157
|
+
// every feature + module router. The safety net: a thrown ApiError, any
|
|
158
|
+
// next(err), and body-parser failures (malformed JSON / oversized body) all
|
|
159
|
+
// come out as the R01 envelope instead of Express's default error page. A
|
|
160
|
+
// handler that already responded is untouched (res.headersSent short-circuits).
|
|
161
|
+
router.use(errorEnvelopeHandler);
|
|
162
|
+
|
|
163
|
+
return router;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
module.exports = { buildGdsRouter };
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// src/bongos/secret-box.js — small AES-256-GCM box for per-builder secrets at rest.
|
|
2
|
+
//
|
|
3
|
+
// First (and only) consumer today: the per-builder Gemini key (task 1013 / ADR
|
|
4
|
+
// 0071). The key is stored ENCRYPTED on `builders.gemini_key_enc`; the master
|
|
5
|
+
// key lives ONLY in server env (BUILDER_SECRET_KEY) — never in the DB and never
|
|
6
|
+
// in the repo — so a database dump alone cannot decrypt anything. This is the
|
|
7
|
+
// containment for the one new risk pragmatic BYOK introduces (the server holding
|
|
8
|
+
// N builder keys so it can sync them down to each builder's own box).
|
|
9
|
+
//
|
|
10
|
+
// Master key resolution mirrors loadSharedGeminiKey() in art-key.js / the Discord
|
|
11
|
+
// loaders in auth.js — env wins, else a local 0600 file for dev:
|
|
12
|
+
// 1. process.env.BUILDER_SECRET_KEY (systemd EnvironmentFile on the droplet)
|
|
13
|
+
// 2. ~/.config/otb/builder-secret.key (single-line key, local dev / operator)
|
|
14
|
+
// The value is 32 bytes encoded as 64 hex chars OR base64 (standard or url). A
|
|
15
|
+
// value of any other decoded length is treated as "not configured" (logged once)
|
|
16
|
+
// so a malformed secret fails CLOSED — set/decrypt is disabled, never weak.
|
|
17
|
+
//
|
|
18
|
+
// Blob format (a single opaque string stored in one text column):
|
|
19
|
+
// v1.<iv_b64url>.<tag_b64url>.<ciphertext_b64url>
|
|
20
|
+
// iv = 12 random bytes (GCM standard); tag = 16-byte GCM auth tag. The version
|
|
21
|
+
// prefix lets us rotate the scheme later without guessing.
|
|
22
|
+
|
|
23
|
+
'use strict';
|
|
24
|
+
|
|
25
|
+
const crypto = require('node:crypto');
|
|
26
|
+
const fs = require('node:fs');
|
|
27
|
+
const path = require('node:path');
|
|
28
|
+
const ic = require('../instance-config');
|
|
29
|
+
|
|
30
|
+
const VERSION = 'v1';
|
|
31
|
+
const IV_BYTES = 12;
|
|
32
|
+
const KEY_BYTES = 32;
|
|
33
|
+
|
|
34
|
+
// The operator-file source (source #2 in loadMasterKey). On the prod droplet
|
|
35
|
+
// this is where the productized provisioning (task 1398) writes the generated
|
|
36
|
+
// master key — beside the other instance-config state, surviving restarts.
|
|
37
|
+
// Routed through instance-config (R61 / task 1200) so the write path is EXACTLY
|
|
38
|
+
// what loadMasterKey() reads via ic.readConfigFileSync, and so a non-OTB instance
|
|
39
|
+
// uses its own configured dir rather than a hard-coded ~/.config/otb.
|
|
40
|
+
function masterKeyFile() {
|
|
41
|
+
return ic.configPath('builder-secret.key');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let _warnedBadKey = false;
|
|
45
|
+
|
|
46
|
+
// Decode a 32-byte master key from hex or base64. Returns a Buffer or null.
|
|
47
|
+
function decodeMasterKey(raw) {
|
|
48
|
+
if (!raw || typeof raw !== 'string') return null;
|
|
49
|
+
const s = raw.trim();
|
|
50
|
+
if (!s) return null;
|
|
51
|
+
// 64 hex chars → 32 bytes.
|
|
52
|
+
if (/^[0-9a-fA-F]{64}$/.test(s)) return Buffer.from(s, 'hex');
|
|
53
|
+
// Otherwise try base64 / base64url.
|
|
54
|
+
try {
|
|
55
|
+
const buf = Buffer.from(s, 'base64');
|
|
56
|
+
if (buf.length === KEY_BYTES) return buf;
|
|
57
|
+
} catch (_) { /* fall through */ }
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Load the master key from env, then the local operator file. Returns Buffer|null.
|
|
62
|
+
function loadMasterKey() {
|
|
63
|
+
const fromEnv = decodeMasterKey(process.env.BUILDER_SECRET_KEY);
|
|
64
|
+
if (fromEnv) return fromEnv;
|
|
65
|
+
// A set-but-malformed env value is an operator mistake worth one loud line —
|
|
66
|
+
// but we still fail closed (return null) rather than fall back to something weak.
|
|
67
|
+
if (process.env.BUILDER_SECRET_KEY && !_warnedBadKey) {
|
|
68
|
+
_warnedBadKey = true;
|
|
69
|
+
console.error('[gds] BUILDER_SECRET_KEY is set but is not a 32-byte hex/base64 value — secret storage disabled until fixed.');
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const raw = ic.readConfigFileSync('builder-secret.key');
|
|
73
|
+
const fromFile = raw && decodeMasterKey(raw);
|
|
74
|
+
if (fromFile) return fromFile;
|
|
75
|
+
} catch (_) { /* not configured */ }
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Is the server able to encrypt/decrypt? (i.e. is a valid master key present?)
|
|
80
|
+
// The set-key route 503s when this is false, so the feature stays dark until an
|
|
81
|
+
// operator provisions BUILDER_SECRET_KEY — exactly the shared-key rollout shape.
|
|
82
|
+
function isConfigured() {
|
|
83
|
+
return !!loadMasterKey();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// provisionMasterKey — generate + persist a master key so the per-builder key
|
|
87
|
+
// feature can turn on WITHOUT a human hand-editing prod secrets (task 1398, the
|
|
88
|
+
// productized fix for blocker 41). The server generates 32 crypto-random bytes
|
|
89
|
+
// and writes them (hex) to the operator file as 0600.
|
|
90
|
+
//
|
|
91
|
+
// SAFETY — this MUST be idempotent and MUST NEVER overwrite an existing key: the
|
|
92
|
+
// master key decrypts every stored builder secret, so regenerating it would brick
|
|
93
|
+
// them all. So:
|
|
94
|
+
// 1. If a valid key already resolves (env or file) → no-op, report it.
|
|
95
|
+
// 2. Otherwise create the file with the `wx` flag (exclusive): if a file is
|
|
96
|
+
// already present (even a malformed one) the write fails EEXIST and we
|
|
97
|
+
// REFUSE rather than clobber — that case needs an operator, not a silent
|
|
98
|
+
// overwrite.
|
|
99
|
+
// `opts` (file/env) exist only so the unit test can drive it against a temp path
|
|
100
|
+
// without touching the real ~/.config/otb; production calls it with no args.
|
|
101
|
+
function provisionMasterKey(opts = {}) {
|
|
102
|
+
const file = opts.file || masterKeyFile();
|
|
103
|
+
const env = opts.env !== undefined ? opts.env : process.env.BUILDER_SECRET_KEY;
|
|
104
|
+
if (decodeMasterKey(env)) return { ok: true, created: false, reason: 'already_configured_env' };
|
|
105
|
+
try {
|
|
106
|
+
if (decodeMasterKey(fs.readFileSync(file, 'utf8'))) {
|
|
107
|
+
return { ok: true, created: false, reason: 'already_configured_file' };
|
|
108
|
+
}
|
|
109
|
+
} catch (_) { /* no readable file yet — fall through to create */ }
|
|
110
|
+
|
|
111
|
+
const key = crypto.randomBytes(KEY_BYTES).toString('hex'); // 64 hex chars = 32 bytes
|
|
112
|
+
try {
|
|
113
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
114
|
+
fs.writeFileSync(file, `${key}\n`, { flag: 'wx', mode: 0o600 }); // wx = fail if it exists
|
|
115
|
+
} catch (e) {
|
|
116
|
+
if (e && e.code === 'EEXIST') {
|
|
117
|
+
// A file is already there but didn't decode as a valid key. Do NOT clobber
|
|
118
|
+
// it — it may be a real key our process just can't read. Operator must look.
|
|
119
|
+
return { ok: false, error: 'key_file_exists_but_invalid' };
|
|
120
|
+
}
|
|
121
|
+
return { ok: false, error: (e && (e.code || e.message)) || 'write_failed' };
|
|
122
|
+
}
|
|
123
|
+
try { fs.chmodSync(file, 0o600); } catch (_) { /* best-effort tighten */ }
|
|
124
|
+
return { ok: true, created: true };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function b64url(buf) {
|
|
128
|
+
return buf.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
129
|
+
}
|
|
130
|
+
function fromB64url(str) {
|
|
131
|
+
return Buffer.from(str.replace(/-/g, '+').replace(/_/g, '/'), 'base64');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Encrypt a UTF-8 plaintext → the opaque "v1.iv.tag.ct" blob. Throws if the
|
|
135
|
+
// master key isn't configured (callers gate on isConfigured() first).
|
|
136
|
+
function encrypt(plaintext) {
|
|
137
|
+
if (typeof plaintext !== 'string' || plaintext.length === 0) {
|
|
138
|
+
throw new Error('secret-box.encrypt: plaintext must be a non-empty string');
|
|
139
|
+
}
|
|
140
|
+
const key = loadMasterKey();
|
|
141
|
+
if (!key) throw new Error('secret-box: master key not configured');
|
|
142
|
+
const iv = crypto.randomBytes(IV_BYTES);
|
|
143
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
|
|
144
|
+
const ct = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
|
|
145
|
+
const tag = cipher.getAuthTag();
|
|
146
|
+
return [VERSION, b64url(iv), b64url(tag), b64url(ct)].join('.');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Decrypt a blob produced by encrypt() → the UTF-8 plaintext. Throws on a bad
|
|
150
|
+
// format, a missing master key, or a failed auth tag (tamper / wrong key).
|
|
151
|
+
function decrypt(blob) {
|
|
152
|
+
if (typeof blob !== 'string' || !blob) throw new Error('secret-box.decrypt: empty blob');
|
|
153
|
+
const parts = blob.split('.');
|
|
154
|
+
if (parts.length !== 4 || parts[0] !== VERSION) {
|
|
155
|
+
throw new Error('secret-box.decrypt: unrecognized blob format');
|
|
156
|
+
}
|
|
157
|
+
const key = loadMasterKey();
|
|
158
|
+
if (!key) throw new Error('secret-box: master key not configured');
|
|
159
|
+
const iv = fromB64url(parts[1]);
|
|
160
|
+
const tag = fromB64url(parts[2]);
|
|
161
|
+
const ct = fromB64url(parts[3]);
|
|
162
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
|
|
163
|
+
decipher.setAuthTag(tag);
|
|
164
|
+
const out = Buffer.concat([decipher.update(ct), decipher.final()]);
|
|
165
|
+
return out.toString('utf8');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = {
|
|
169
|
+
VERSION,
|
|
170
|
+
masterKeyFile,
|
|
171
|
+
isConfigured,
|
|
172
|
+
provisionMasterKey,
|
|
173
|
+
encrypt,
|
|
174
|
+
decrypt,
|
|
175
|
+
// exported for tests
|
|
176
|
+
decodeMasterKey,
|
|
177
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// MAS — single source of truth for the security-relevant file surfaces the
|
|
2
|
+
// system watches. Used by BOTH the Conductor hook (.claude/hooks/conductor.js,
|
|
3
|
+
// to decide when to dispatch the Hacker) and the dispatcher CLI
|
|
4
|
+
// (scripts/gds/conductor-dispatch.js, for `auto` specialist selection).
|
|
5
|
+
//
|
|
6
|
+
// Defined ONCE here so the two can't drift — the Phase 4 dogfood (#439) had
|
|
7
|
+
// the Hacker AND Quality workers independently flag that the set was
|
|
8
|
+
// hand-copied into both files, and that a drift would silently suppress
|
|
9
|
+
// auto-dispatch for a newly-unrecognized surface. This module removes that
|
|
10
|
+
// whole class of bug.
|
|
11
|
+
//
|
|
12
|
+
// Matched against repo-relative POSIX paths.
|
|
13
|
+
|
|
14
|
+
const SENSITIVE_SURFACES = [
|
|
15
|
+
{ re: /^migrations\//, label: 'migrations/' },
|
|
16
|
+
{ re: /^src\/bongos\/routes\//, label: 'src/bongos/routes/' },
|
|
17
|
+
{ re: /(^|\/)auth\.js$/, label: 'auth' },
|
|
18
|
+
{ re: /(^|\/)server\.js$/, label: 'server.js' },
|
|
19
|
+
{ re: /(^|\/)Caddyfile$/, label: 'Caddyfile' },
|
|
20
|
+
// This file itself: editing the security-surface definitions IS a
|
|
21
|
+
// security-relevant change, so a change here self-triggers a Hacker review
|
|
22
|
+
// (the panel flagged on #439 that the defs file was conspicuously absent).
|
|
23
|
+
{ re: /(^|\/)sensitive-surfaces\.js$/, label: 'security-surface-defs' },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
function isSensitive(file) {
|
|
27
|
+
return SENSITIVE_SURFACES.some((s) => s.re.test(file));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = { SENSITIVE_SURFACES, isSensitive };
|