@bongos/core 1.18.0 → 1.18.18
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 +1740 -640
- package/.claude/skills/builder-box/SKILL.md +6 -0
- package/.claude/skills/builder-sequence/SKILL.md +97 -0
- package/.claude/skills/builder-ship/SKILL.md +8 -2
- package/.claude/skills/builder-start/SKILL.md +11 -0
- package/.claude/skills/builder-sync/SKILL.md +41 -0
- package/.claude/skills/fix-task/SKILL.md +64 -0
- package/.claude/skills/goal-create/SKILL.md +158 -0
- package/.claude/skills/goal-review/SKILL.md +3 -1
- package/.claude/skills/idea-triage/SKILL.md +14 -8
- package/.claude/skills/merge-mode/SKILL.md +2 -2
- package/.claude/skills/new-project/SKILL.md +1 -0
- package/.claude/skills/planning-session/SKILL.md +45 -18
- package/.env.local.example +4 -3
- package/README.md +5 -3
- package/bin/bongos.js +1 -0
- package/clients/bongos-client/README.md +2 -2
- package/clients/bongos-client/bongos-client.global.js +82 -18
- package/clients/bongos-client/index.cjs +82 -18
- package/clients/bongos-client/index.d.ts +131 -29
- package/clients/bongos-client/index.mjs +82 -18
- package/config/branding.neutral.json +11 -2
- package/config/governance.neutral.json +21 -0
- package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +24 -0
- package/docs/adr/0090-metic-task-authoring.md +1 -1
- package/docs/adr/0142-project-context-is-prose-only.md +41 -0
- package/docs/adr/0143-onboarding-repo-picker-oauth-scope.md +35 -0
- package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +41 -0
- package/docs/adr/0144-federated-single-logout-backchannel.md +42 -0
- package/docs/adr/0145-devbox-app-branding-driven-module.md +44 -0
- package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +62 -0
- package/docs/adr/0146-configurable-reward-mode-cost-plus-only.md +53 -0
- package/docs/adr/0147-standalone-live-docs-regen.md +39 -0
- package/docs/adr/0148-task-scoped-box-source-access.md +48 -0
- package/docs/adr/0149-bongos-dev-local-launcher.md +57 -0
- package/docs/adr/0150-box-first-boot-bringup-vendored-instances.md +68 -0
- package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +229 -0
- package/docs/adr/0152-landing-gate-served-by-the-core-app.md +92 -0
- package/docs/adr/0152-metic-task-abandonment.md +67 -0
- package/docs/adr/0153-sequential-chain-runner.md +51 -0
- package/docs/adr/0154-goal-owner-criterion-authoring.md +86 -0
- package/docs/adr/README.md +15 -2
- package/docs/api/openapi.json +2648 -483
- package/docs/api-reference.md +73 -13
- package/docs/architecture.md +4 -2
- package/docs/branding-contract.md +3 -1
- package/docs/canonical-permissions.md +21 -8
- package/docs/file-map.md +15 -7
- package/docs/onboarding/diagrams/01-task-lifecycle.mmd +2 -2
- package/docs/onboarding/diagrams/02-rank-ladder.mmd +3 -1
- package/docs/onboarding/diagrams/05-versioning.mmd +1 -3
- package/docs/onboarding/diagrams/assertions.json +4 -7
- package/docs/onboarding/drachmae-and-karma.md +3 -3
- package/docs/onboarding/primer.md +17 -16
- package/docs/onboarding/slash-commands.md +124 -0
- package/docs/recipes/builder-box-lifecycle.md +23 -0
- package/docs/recipes/devbox-app-release.md +14 -4
- package/docs/recipes/instance-first-run.md +16 -0
- package/docs/recipes/local-dev.md +81 -0
- package/docs/recipes/ops-gotchas.md +19 -1
- package/docs/recipes/overnight-builder.md +1 -1
- package/docs/recipes/packaging-the-core.md +13 -0
- package/docs/recipes/parallel-goal-waves.md +174 -0
- package/docs/recipes/ship-and-regrade.md +2 -2
- package/docs/recipes/standalone-live-docs.md +48 -0
- package/docs/recipes/upgrading-the-core.md +5 -2
- package/docs/recipes/work-on-a-task-from-your-dev-box.md +108 -0
- package/migrations/003_pms.sql +6 -7
- package/migrations/006_pms_v2.sql +3 -31
- package/migrations/039_newcomer_friendly_column.sql +5 -0
- package/migrations/102_remove_box_first_provision_approval.sql +4 -0
- package/migrations/core_192_github_oauth_tokens.sql +33 -0
- package/migrations/core_193_task_needs_rebase.sql +28 -0
- package/migrations/core_194_confirmed_backlog_clawback.sql +63 -0
- package/migrations/core_195_idea_triage_provenance.sql +57 -0
- package/migrations/core_196_session_reward_topup.sql +69 -0
- package/modules/autonomy/pollers/routine-timers.js +9 -8
- package/modules/builder-settings/wandering-prefs.js +61 -18
- package/modules/dev-box/app/README.md +73 -0
- package/modules/dev-box/app/assets/tray/mac-alertTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-alertTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-busyTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-busyTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-offTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-offTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-onTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-onTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/win-alert.png +0 -0
- package/modules/dev-box/app/assets/tray/win-busy.png +0 -0
- package/modules/dev-box/app/assets/tray/win-off.png +0 -0
- package/modules/dev-box/app/assets/tray/win-on.png +0 -0
- package/modules/dev-box/app/build-resources/dmg-background.png +0 -0
- package/modules/dev-box/app/build-resources/dmg-background@2x.png +0 -0
- package/modules/dev-box/app/build-resources/icon.png +0 -0
- package/modules/dev-box/app/electron-builder.tmpl.yml +95 -0
- package/modules/dev-box/app/electron-builder.yml +95 -0
- package/modules/dev-box/app/package-lock.json +5291 -0
- package/modules/dev-box/app/package.json +30 -0
- package/modules/dev-box/app/renderer/app.js +319 -0
- package/modules/dev-box/app/renderer/index.html +45 -0
- package/modules/dev-box/app/renderer/styles.css +246 -0
- package/modules/dev-box/app/renderer/theme.generated.css +16 -0
- package/modules/dev-box/app/scripts/apply-dmg-backdrop.sh +82 -0
- package/modules/dev-box/app/scripts/dmgbuild-settings.py +39 -0
- package/modules/dev-box/app/scripts/gen-brand.js +138 -0
- package/modules/dev-box/app/scripts/gen-dmg-backdrop.py +323 -0
- package/modules/dev-box/app/scripts/gen-icons.js +286 -0
- package/modules/dev-box/app/scripts/vendor-client.js +23 -0
- package/modules/dev-box/app/src/box-controller.js +287 -0
- package/modules/dev-box/app/src/brand.generated.json +13 -0
- package/modules/dev-box/app/src/brand.js +16 -0
- package/modules/dev-box/app/src/config.js +19 -0
- package/modules/dev-box/app/src/gds-client.js +90 -0
- package/modules/dev-box/app/src/main.js +610 -0
- package/modules/dev-box/app/src/pairing.js +57 -0
- package/modules/dev-box/app/src/preload.js +29 -0
- package/modules/dev-box/app/src/session-store.js +58 -0
- package/modules/dev-box/app/src/ssh-setup.js +569 -0
- package/modules/dev-box/app/src/task-picker.js +70 -0
- package/modules/dev-box/app/src/tray.js +99 -0
- package/modules/dev-box/app/src/updater.js +55 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +698 -0
- package/modules/dev-box/app/test/unit.mjs +526 -0
- package/modules/dev-box/box-access.js +121 -4
- package/modules/dev-box/boxes.js +20 -0
- package/modules/dev-box/module.json +1 -1
- package/modules/dev-box/routes/box.js +87 -3
- package/modules/economy/credits.js +116 -25
- package/modules/economy/reward.js +8 -0
- package/modules/economy/streak.js +2 -1
- package/modules/governance/CLAUDE.md +15 -0
- package/modules/governance/catalog.js +419 -0
- package/modules/governance/config.js +174 -0
- package/modules/governance/db.js +125 -0
- package/modules/governance/migrations/governance_001_tables.sql +81 -0
- package/modules/governance/migrations/governance_002_seed_and_backfill.sql +103 -0
- package/modules/governance/migrations/governance_003_task_abandon_metic.sql +28 -0
- package/modules/governance/migrations/governance_004_criterion_create.sql +39 -0
- package/modules/governance/migrations/governance_005_resync_builder_rank_roles.sql +56 -0
- package/modules/governance/module.json +10 -0
- package/modules/governance/protected-surfaces.js +88 -0
- package/modules/governance/protected-surfaces.json +80 -0
- package/modules/governance/rank-roles.js +83 -0
- package/modules/governance/resolver.js +221 -0
- package/modules/governance/routes/governance.js +89 -0
- package/modules/governance/routes/role-sync.js +49 -0
- package/modules/governance/session-scopes.js +127 -0
- package/modules/governance/session-scopes.json +38 -0
- package/modules/hall-ui/public/atlas.css +117 -0
- package/modules/hall-ui/public/atlas.html +3 -114
- package/modules/hall-ui/public/brand-apply.js +34 -6
- package/modules/hall-ui/public/builders.js +187 -219
- package/modules/hall-ui/public/diagrams.html +2 -0
- package/modules/hall-ui/public/dom-utils.js +27 -0
- package/modules/hall-ui/public/drachmae.html +2 -0
- package/modules/hall-ui/public/drachmae.js +54 -1
- package/modules/hall-ui/public/gate.css +98 -0
- package/modules/hall-ui/public/gate.html +3 -95
- package/modules/hall-ui/public/goal-inbox.js +4 -1
- package/modules/hall-ui/public/goals-page.js +626 -114
- package/modules/hall-ui/public/goals.css +79 -1
- package/modules/hall-ui/public/goals.html +38 -11
- package/modules/hall-ui/public/hall-widgets.js +62 -52
- package/modules/hall-ui/public/harbor.css +123 -0
- package/modules/hall-ui/public/harbor.html +3 -120
- package/modules/hall-ui/public/index.html +11 -4
- package/modules/hall-ui/public/instances-panel.js +4 -1
- package/modules/hall-ui/public/modules.css +63 -0
- package/modules/hall-ui/public/modules.html +3 -60
- package/modules/hall-ui/public/my-projects.html +78 -0
- package/modules/hall-ui/public/my-projects.js +142 -0
- package/modules/hall-ui/public/new-project-wizard.js +7 -3
- package/modules/hall-ui/public/not-ready.html +2 -0
- package/modules/hall-ui/public/pair.css +73 -0
- package/modules/hall-ui/public/pair.html +3 -70
- package/modules/hall-ui/public/palette.js +302 -0
- package/modules/hall-ui/public/primer.css +13 -0
- package/modules/hall-ui/public/primer.html +2 -0
- package/modules/hall-ui/public/profile.html +2 -0
- package/modules/hall-ui/public/ranks.html +2 -0
- package/modules/hall-ui/public/roadmap.css +179 -0
- package/modules/hall-ui/public/roadmap.html +9 -172
- package/modules/hall-ui/public/roadmap.js +329 -316
- package/modules/hall-ui/public/scouting.html +45 -0
- package/modules/hall-ui/public/scouting.js +73 -0
- package/modules/hall-ui/public/sessions.css +16 -0
- package/modules/hall-ui/public/sessions.html +3 -13
- package/modules/hall-ui/public/settings.html +2 -0
- package/modules/hall-ui/public/settings.js +4 -4
- package/modules/hall-ui/public/shell.js +143 -18
- package/modules/hall-ui/public/style.css +231 -39
- package/modules/hall-ui/public/task-detail.js +347 -26
- package/modules/hall-ui/public/task.html +6 -1
- package/modules/hall-ui/public/watch.html +2 -0
- package/modules/hall-ui/public/work.html +8 -6
- package/modules/hall-ui/public/work.js +1 -1
- package/modules/ideas/inbox.js +61 -11
- package/modules/ideas/routes/inbox.js +23 -0
- package/modules/lifecycle/claim-eligibility.js +72 -0
- package/modules/lifecycle/db.js +519 -139
- package/modules/lifecycle/done-when.js +18 -3
- package/modules/lifecycle/github-push.js +19 -2
- package/modules/lifecycle/goal-advisory.js +114 -0
- package/modules/lifecycle/goal-authz.js +62 -0
- package/modules/lifecycle/lifecycle.js +9 -0
- package/modules/lifecycle/publish-reconciler.js +109 -6
- package/modules/lifecycle/routes/claims.js +68 -23
- package/modules/lifecycle/routes/done-when.js +110 -15
- package/modules/lifecycle/routes/goals.js +8 -38
- package/modules/lifecycle/routes/tasks.js +38 -6
- package/modules/lifecycle/ship-card.js +6 -0
- package/modules/onboarding/onboarding-state.js +1 -1
- package/modules/platform-identity/CLAUDE.md +15 -0
- package/modules/platform-identity/hub-device.js +147 -0
- package/modules/platform-identity/hub-keys.js +151 -0
- package/modules/platform-identity/migrations/platform_identity_001_tables.sql +114 -0
- package/modules/platform-identity/migrations/platform_identity_002_client_origin_index.sql +18 -0
- package/modules/platform-identity/migrations/platform_identity_003_project_memberships.sql +42 -0
- package/modules/platform-identity/migrations/platform_identity_004_projects.sql +44 -0
- package/modules/platform-identity/migrations/platform_identity_005_builder_activity.sql +42 -0
- package/modules/platform-identity/module.json +18 -0
- package/modules/platform-identity/platform-identity.js +531 -0
- package/modules/platform-identity/pollers/code-sweep.js +43 -0
- package/modules/platform-identity/routes/my-projects.js +140 -0
- package/modules/platform-identity/routes/projects.js +107 -0
- package/modules/platform-identity/routes/scouting.js +35 -0
- package/modules/platform-identity/routes/sso.js +402 -0
- package/modules/platform-identity/tests/platform-identity.mjs +388 -0
- package/modules/platform-identity/ui/.gitkeep +0 -0
- package/modules/security/routes/reports.js +10 -0
- package/modules/sessions/db.js +166 -21
- package/modules/sessions/module.json +1 -1
- package/modules/sessions/pollers/session-reward-reconcile.js +78 -0
- package/modules/sessions/routes/sessions.js +33 -0
- package/modules/status-ui/public/explore.html +54 -0
- package/modules/status-ui/public/explore.js +67 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/anim/idle/frame_00.webp +0 -0
- package/public-landing/assets/anim/idle/frame_01.webp +0 -0
- package/public-landing/assets/anim/idle/frame_02.webp +0 -0
- package/public-landing/assets/anim/idle/frame_03.webp +0 -0
- package/public-landing/assets/anim/idle/frame_04.webp +0 -0
- package/public-landing/assets/anim/idle/frame_05.webp +0 -0
- package/public-landing/assets/anim/idle/frame_06.webp +0 -0
- package/public-landing/assets/anim/idle/frame_07.webp +0 -0
- package/public-landing/assets/anim/idle/frame_08.webp +0 -0
- package/public-landing/assets/anim/idle/frame_09.webp +0 -0
- package/public-landing/assets/anim/idle/frame_10.webp +0 -0
- package/public-landing/assets/anim/idle/frame_11.webp +0 -0
- package/public-landing/assets/anim/idle/frame_12.webp +0 -0
- package/public-landing/assets/anim/idle/frame_13.webp +0 -0
- package/public-landing/assets/anim/idle/frame_14.webp +0 -0
- package/public-landing/assets/anim/idle/frame_15.webp +0 -0
- package/public-landing/assets/anim/idle/frame_16.webp +0 -0
- package/public-landing/assets/anim/idle/frame_17.webp +0 -0
- package/public-landing/assets/anim/idle/frame_18.webp +0 -0
- package/public-landing/assets/anim/idle/frame_19.webp +0 -0
- package/public-landing/assets/anim/idle/frame_20.webp +0 -0
- package/public-landing/assets/anim/idle/frame_21.webp +0 -0
- package/public-landing/assets/anim/idle/frame_22.webp +0 -0
- package/public-landing/assets/anim/idle/frame_23.webp +0 -0
- package/public-landing/assets/anim/idle/frame_24.webp +0 -0
- package/public-landing/assets/anim/idle/frame_25.webp +0 -0
- package/public-landing/assets/anim/idle/frame_26.webp +0 -0
- package/public-landing/assets/anim/idle/frame_27.webp +0 -0
- package/public-landing/assets/anim/idle/frame_28.webp +0 -0
- package/public-landing/assets/anim/idle/frame_29.webp +0 -0
- package/public-landing/assets/anim/idle/frame_30.webp +0 -0
- package/public-landing/assets/anim/idle/frame_31.webp +0 -0
- package/public-landing/assets/anim/idle/frame_32.webp +0 -0
- package/public-landing/assets/anim/idle/frame_33.webp +0 -0
- package/public-landing/assets/anim/idle/frame_34.webp +0 -0
- package/public-landing/assets/anim/idle/frame_35.webp +0 -0
- package/public-landing/assets/anim/idle/frame_36.webp +0 -0
- package/public-landing/assets/anim/idle/frame_37.webp +0 -0
- package/public-landing/assets/anim/idle/frame_38.webp +0 -0
- package/public-landing/assets/anim/idle/frame_39.webp +0 -0
- package/public-landing/assets/anim/idle/frame_40.webp +0 -0
- package/public-landing/assets/anim/idle/frame_41.webp +0 -0
- package/public-landing/assets/anim/idle/frame_42.webp +0 -0
- package/public-landing/assets/anim/idle/frame_43.webp +0 -0
- package/public-landing/create.html +252 -62
- package/public-landing/gate/README.md +137 -0
- package/public-landing/gate/dispmaps/bar.png +0 -0
- package/public-landing/gate/dispmaps/flat.png +0 -0
- package/public-landing/gate/dispmaps/key.png +0 -0
- package/public-landing/gate/index.html +587 -0
- package/public-landing/gate/previews/cloud-bongos.jpg +0 -0
- package/public-landing/gate/previews/off-the-boats.jpg +0 -0
- package/public-landing/gate/space.css +799 -0
- package/public-landing/gate/space.js +1826 -0
- package/public-landing/gate/sprites/enter.png +0 -0
- package/public-landing/gate/sprites/search.png +0 -0
- package/public-landing/gate/sprites/terminal-blank.png +0 -0
- package/public-landing/gate/sprites/tile.png +0 -0
- package/public-landing/world/assets/clouds/cloud-island-large.png +0 -0
- package/public-landing/world/assets/clouds/cloud-puff.png +0 -0
- package/public-landing/world/assets/creatures/creature-whale-cargo.png +0 -0
- package/public-landing/world/assets/creatures/creature-whale-glide.png +0 -0
- package/public-landing/world/assets/plates/plate-clouds-near.png +0 -0
- package/public-landing/world/assets/plates/scene-establishing.png +0 -0
- package/scripts/gds/abandon.js +6 -4
- package/scripts/gds/api.js +10 -5
- package/scripts/gds/api.ps1 +26 -0
- package/scripts/gds/api.sh +6 -0
- package/scripts/gds/audit-ships.js +7 -1
- package/scripts/gds/backfill-sessions.js +78 -18
- package/scripts/gds/backup.js +23 -1
- package/scripts/gds/box-connect-lib.js +124 -31
- package/scripts/gds/box-sync.js +66 -0
- package/scripts/gds/box.js +225 -53
- package/scripts/gds/cf-tunnel.js +145 -6
- package/scripts/gds/claim.js +34 -3
- package/scripts/gds/cli-lib.js +161 -21
- package/scripts/gds/code.js +6 -2
- package/scripts/gds/deploy-divergence.js +209 -0
- package/scripts/gds/dev-lib.js +309 -0
- package/scripts/gds/dev.js +322 -0
- package/scripts/gds/doctor.js +90 -61
- package/scripts/gds/fetch-art-key.js +1 -1
- package/scripts/gds/fetch-sound-prefs.js +2 -2
- package/scripts/gds/fitness.js +228 -12
- package/scripts/gds/gds-db-backup.service +16 -1
- package/scripts/gds/gds-db-offsite.service +9 -1
- package/scripts/gds/gen-api-client.js +1 -1
- package/scripts/gds/gen-api-docs.js +36 -14
- package/scripts/gds/gen-diagrams.js +45 -28
- package/scripts/gds/gen-file-map.js +2 -1
- package/scripts/gds/gen-freshness.js +32 -0
- package/scripts/gds/gen-repo-map.js +3 -2
- package/scripts/gds/gen-session-index.js +14 -5
- package/scripts/gds/hooks/pre-push.js +2 -2
- package/scripts/gds/init.js +60 -3
- package/scripts/gds/install-git-hooks.js +1 -1
- package/scripts/gds/key-card.js +15 -6
- package/scripts/gds/key-status.js +1 -1
- package/scripts/gds/linkify-refs.js +35 -9
- package/scripts/gds/lint-migrations.js +102 -0
- package/scripts/gds/login.js +58 -11
- package/scripts/gds/mirror-redact.js +5 -0
- package/scripts/gds/package-core.js +263 -4
- package/scripts/gds/paste-token.js +7 -1
- package/scripts/gds/preflight.js +126 -0
- package/scripts/gds/provision.js +268 -19
- package/scripts/gds/publish-manifest.js +22 -1
- package/scripts/gds/reauth.js +7 -3
- package/scripts/gds/regen-instance-docs.js +47 -0
- package/scripts/gds/run-unit-tests.js +42 -16
- package/scripts/gds/seed-bongos-v1-seo-tasks.js +104 -0
- package/scripts/gds/seed-bv1-profiles-tasks.js +126 -0
- package/scripts/gds/sequence.js +425 -0
- package/scripts/gds/session-cost.js +10 -1
- package/scripts/gds/setup.js +72 -5
- package/scripts/gds/shell.js +5 -3
- package/scripts/gds/ship.js +433 -59
- package/scripts/gds/smoke-gds.js +139 -8
- package/scripts/gds/start.js +171 -22
- package/scripts/gds/status.js +1 -1
- package/scripts/gds/triage.js +10 -9
- package/scripts/gds/upgrade.js +271 -7
- package/scripts/migrate.sh +10 -0
- package/scripts/status-mirror-sync.js +114 -84
- package/src/bongos/api-errors.js +1 -0
- package/src/bongos/auth.js +809 -107
- package/src/bongos/db-kernel.js +27 -0
- package/src/bongos/db.js +105 -0
- package/src/bongos/github-repos.js +93 -0
- package/src/bongos/module-scope-map.js +27 -1
- package/src/bongos/permission-path-check.js +136 -102
- package/src/bongos/repo-info.js +47 -11
- package/src/bongos/route-rank-check.js +429 -46
- package/src/bongos/routes/_helpers.js +12 -1
- package/src/bongos/routes/auth.js +312 -13
- package/src/bongos/routes/backup.js +58 -2
- package/src/bongos/routes/github.js +90 -0
- package/src/bongos/routes/instance.js +15 -3
- package/src/bongos/routes/me.js +35 -1
- package/src/bongos/routes.js +2 -0
- package/src/bongos/serve-internal.js +84 -15
- package/src/branding.js +49 -2
- package/src/instance-config.js +46 -0
- package/src/module-api.js +140 -1
- package/src/platform-server.js +86 -9
- package/tests/abandon_task.mjs +59 -3
- package/tests/api_cli_flags.mjs +53 -0
- package/tests/auth_page_gate.mjs +13 -0
- package/tests/backfill_sessions.mjs +127 -1
- package/tests/backup_cli.mjs +54 -0
- package/tests/bongos_box_connect.mjs +77 -0
- package/tests/box_access.mjs +130 -1
- package/tests/box_credential.mjs +125 -0
- package/tests/box_host_keys.mjs +24 -0
- package/tests/box_infra_resolve.mjs +149 -0
- package/tests/box_scope_session.mjs +6 -2
- package/tests/box_sync.mjs +55 -0
- package/tests/box_task_scope.mjs +99 -0
- package/tests/branding.mjs +41 -23
- package/tests/cf_ruleset_preflight.mjs +142 -0
- package/tests/cf_tunnel.mjs +37 -0
- package/tests/claim_gate_rebase.mjs +98 -0
- package/tests/clawback_confirmed_backlog.mjs +103 -0
- package/tests/cli_lib_formatters.mjs +20 -0
- package/tests/confirm_attribution.mjs +30 -46
- package/tests/credit_grant.mjs +198 -10
- package/tests/criterion_authoring_gate.mjs +272 -0
- package/tests/criterion_progress.mjs +33 -1
- package/tests/dev_lib.mjs +253 -0
- package/tests/devbox_artifact_gate.mjs +75 -0
- package/tests/devbox_dmg_backdrop.mjs +137 -0
- package/tests/devbox_icons.mjs +304 -0
- package/tests/devbox_installer_brand.mjs +232 -0
- package/tests/devbox_key_register.mjs +234 -0
- package/tests/docs_openapi_route.mjs +110 -0
- package/tests/doctor_hooks.mjs +141 -0
- package/tests/extract_json.mjs +140 -0
- package/tests/fitness.mjs +89 -0
- package/tests/gen_freshness.mjs +96 -0
- package/tests/github_repos_helpers.mjs +91 -0
- package/tests/github_token_store.mjs +121 -0
- package/tests/goal_advisory.mjs +251 -0
- package/tests/goal_criterion_confirm_ui.mjs +269 -0
- package/tests/goal_routes.mjs +59 -4
- package/tests/goal_tier.mjs +12 -3
- package/tests/governance_catalog.mjs +129 -0
- package/tests/governance_claim_eligibility.mjs +262 -0
- package/tests/governance_config.mjs +187 -0
- package/tests/governance_ownership_scope.mjs +410 -0
- package/tests/governance_page_gates.mjs +324 -0
- package/tests/governance_parity.mjs +336 -0
- package/tests/governance_principals.mjs +232 -0
- package/tests/governance_protected_surfaces.mjs +208 -0
- package/tests/governance_require_permission.mjs +223 -0
- package/tests/governance_resolver.mjs +84 -0
- package/tests/governance_role_sync.mjs +231 -0
- package/tests/governance_seed.mjs +127 -0
- package/tests/governance_session_scope.mjs +434 -0
- package/tests/governance_vanilla_boot.mjs +203 -0
- package/tests/grade_attribution.mjs +7 -7
- package/tests/hall_audit.mjs +223 -0
- package/tests/hall_nav.mjs +191 -0
- package/tests/hall_palette.mjs +206 -0
- package/tests/hall_signout.mjs +124 -0
- package/tests/hook_user_agents.mjs +10 -0
- package/tests/idea_triage.mjs +162 -0
- package/tests/idp_device_exchange.mjs +198 -0
- package/tests/idp_federation.mjs +100 -0
- package/tests/init.mjs +51 -0
- package/tests/instance_config.mjs +65 -0
- package/tests/instance_mismatch_guard.mjs +23 -6
- package/tests/instance_release_config.mjs +104 -0
- package/tests/linkify_refs.mjs +15 -2
- package/tests/migrations_forward_safe.mjs +86 -0
- package/tests/module_api.mjs +1 -1
- package/tests/module_contributions.mjs +55 -0
- package/tests/module_loader.mjs +10 -5
- package/tests/module_scope_active_claims.mjs +94 -0
- package/tests/needs_rebase.mjs +92 -0
- package/tests/one_active_claim_per_session.mjs +76 -0
- package/tests/override_attribution.mjs +10 -8
- package/tests/override_request_ownership.mjs +8 -4
- package/tests/package_core.mjs +246 -1
- package/tests/parse_cookie_decode.mjs +42 -0
- package/tests/pay_on_land.mjs +129 -0
- package/tests/platform_boot.mjs +100 -1
- package/tests/post_login_landing.mjs +42 -0
- package/tests/preflight_checks.mjs +72 -0
- package/tests/provision.mjs +289 -7
- package/tests/pruned_lockfile_integrity.mjs +79 -0
- package/tests/publish_branch_route.mjs +53 -0
- package/tests/publish_reconciler.mjs +187 -2
- package/tests/repo_info_binding.mjs +248 -0
- package/tests/reward_gate.mjs +11 -2
- package/tests/reward_mode_cost_plus_only.mjs +116 -0
- package/tests/reward_mode_surfacing.mjs +168 -0
- package/tests/route_permission_check.mjs +301 -0
- package/tests/route_rank_check.mjs +254 -12
- package/tests/route_validation.mjs +30 -0
- package/tests/sequence.mjs +267 -0
- package/tests/session_digest.mjs +44 -0
- package/tests/session_index.mjs +18 -6
- package/tests/session_records.mjs +39 -1
- package/tests/session_reward_on_land.mjs +381 -0
- package/tests/session_reward_reconcile.mjs +229 -0
- package/tests/ship_api_client_pathspec.mjs +100 -0
- package/tests/ship_base_flag.mjs +93 -0
- package/tests/ship_ci_deploy.mjs +140 -3
- package/tests/ship_upstream_deletion.mjs +57 -0
- package/tests/smoke_target.mjs +233 -0
- package/tests/start_env_guard.mjs +87 -0
- package/tests/start_rebase_warning.mjs +103 -0
- package/tests/status_mirror_sync.mjs +122 -0
- package/tests/stop_refcheck.mjs +19 -1
- package/tests/task_goal_link.mjs +15 -6
- package/tests/upgrade.mjs +393 -5
- package/tests/web_admission_status.mjs +162 -0
- package/tests/write_validation_gaps.mjs +110 -0
- package/.gitignore +0 -91
- package/docs/adr/0139-platform-history-migration-to-cloudbongos.md +0 -94
- package/docs/adr/0140-cloudbongos-standalone-reprovision.md +0 -43
- package/scripts/hall-preview/fixtures/access-requests.json +0 -20
- package/scripts/hall-preview/fixtures/achievements.json +0 -76
- package/scripts/hall-preview/fixtures/analytics__builder.json +0 -251
- package/scripts/hall-preview/fixtures/audit-log.json +0 -68
- package/scripts/hall-preview/fixtures/blockers__detail.json +0 -12
- package/scripts/hall-preview/fixtures/box__me.json +0 -5
- package/scripts/hall-preview/fixtures/boxes__cost-ledger.json +0 -69
- package/scripts/hall-preview/fixtures/builders__active-claims.json +0 -1
- package/scripts/hall-preview/fixtures/builders__directory.json +0 -81
- package/scripts/hall-preview/fixtures/builders__roster.json +0 -48
- package/scripts/hall-preview/fixtures/goals.json +0 -502
- package/scripts/hall-preview/fixtures/goals__25.json +0 -96
- package/scripts/hall-preview/fixtures/goals__26.json +0 -67
- package/scripts/hall-preview/fixtures/goals__3.json +0 -103
- package/scripts/hall-preview/fixtures/goals__35.json +0 -49
- package/scripts/hall-preview/fixtures/goals__conflicts.json +0 -154
- package/scripts/hall-preview/fixtures/goals__detail.json +0 -96
- package/scripts/hall-preview/fixtures/goals__inbox.json +0 -5
- package/scripts/hall-preview/fixtures/goals__requests.json +0 -3
- package/scripts/hall-preview/fixtures/grades__by-builder.json +0 -32
- package/scripts/hall-preview/fixtures/inbox.json +0 -330
- package/scripts/hall-preview/fixtures/inbox__detail.json +0 -15
- package/scripts/hall-preview/fixtures/instance.json +0 -124
- package/scripts/hall-preview/fixtures/leaderboard.json +0 -184
- package/scripts/hall-preview/fixtures/me.json +0 -476
- package/scripts/hall-preview/fixtures/me__art-key__own.json +0 -6
- package/scripts/hall-preview/fixtures/me__event-sound-prefs.json +0 -209
- package/scripts/hall-preview/fixtures/me__recent-ships.json +0 -304
- package/scripts/hall-preview/fixtures/me__render.json +0 -5
- package/scripts/hall-preview/fixtures/me__skill-prefs.json +0 -143
- package/scripts/hall-preview/fixtures/me__sound-prefs.json +0 -67
- package/scripts/hall-preview/fixtures/me__wandering.json +0 -43
- package/scripts/hall-preview/fixtures/override-requests.json +0 -15
- package/scripts/hall-preview/fixtures/provisioning__fleet.json +0 -1
- package/scripts/hall-preview/fixtures/provisioning__fleet__cost-ledger.json +0 -1
- package/scripts/hall-preview/fixtures/provisioning__instances.json +0 -1
- package/scripts/hall-preview/fixtures/public__analytics__ecosystem.json +0 -516
- package/scripts/hall-preview/fixtures/public__bounty-table.json +0 -37
- package/scripts/hall-preview/fixtures/public__cost-summary.json +0 -742
- package/scripts/hall-preview/fixtures/public__estimation-drift.json +0 -41
- package/scripts/hall-preview/fixtures/public__grades.json +0 -50
- package/scripts/hall-preview/fixtures/public__progress.json +0 -124
- package/scripts/hall-preview/fixtures/public__recent-shipped.json +0 -426
- package/scripts/hall-preview/fixtures/public__repo-health.json +0 -160
- package/scripts/hall-preview/fixtures/public__repo-info.json +0 -5
- package/scripts/hall-preview/fixtures/security__docs.json +0 -10
- package/scripts/hall-preview/fixtures/security__reports.json +0 -31
- package/scripts/hall-preview/fixtures/sessions__search.json +0 -9
- package/scripts/hall-preview/fixtures/tasks.json +0 -2420
- package/scripts/hall-preview/fixtures/tasks__claimable.json +0 -2555
- package/scripts/hall-preview/fixtures/tasks__detail.json +0 -111
- package/scripts/hall-preview/fixtures/tasks__peer-votes__feed.json +0 -330
- package/scripts/hall-preview/fixtures/versions.json +0 -89
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
// permission-sensitive path" a DETECTABLE, GATEABLE event — exactly the way
|
|
10
10
|
// route-rank-check.js makes "an ungated write route" detectable.
|
|
11
11
|
//
|
|
12
|
-
// This module is PURE and dependency-free (no
|
|
13
|
-
// run in three places with identical logic:
|
|
12
|
+
// This module is PURE and dependency-free (no pg, no network, no require of any
|
|
13
|
+
// other repo module) so it can run in three places with identical logic:
|
|
14
14
|
// 1. the LOCAL pre-push git hook (scripts/gds/hooks/pre-push.js) — fast,
|
|
15
15
|
// cooperative, blocks the honest builder before the push leaves the box;
|
|
16
16
|
// 2. the GRADER pre-pass (modules/grading/grader.js) — folds a finding into the panel
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
|
|
26
26
|
'use strict';
|
|
27
27
|
|
|
28
|
+
const fs = require('node:fs');
|
|
29
|
+
const path = require('node:path');
|
|
30
|
+
|
|
28
31
|
// Rank → tier. MUST mirror REQUIRES_RANK_TIER in src/bongos/db.js. We keep a LOCAL
|
|
29
32
|
// copy (not an import) so this module stays dependency-free for the client-side
|
|
30
33
|
// pre-push hook; tests/permission_path.mjs asserts the two never drift (the
|
|
@@ -32,87 +35,82 @@
|
|
|
32
35
|
// reintroduce here).
|
|
33
36
|
const RANK_TIER = { xenos: 1, thetes: 2, metic: 3, archon: 4 };
|
|
34
37
|
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
38
|
+
// ── the protected-surface REGISTRY (BV1.R101, ADR 0151 §4) ──────────────────
|
|
39
|
+
//
|
|
40
|
+
// GOVERNANCE OWNS THE DATA; THE SUBSTRATE STAYS THE ENFORCER. Which paths are
|
|
41
|
+
// protected, at what rank floor, mapped to which `system: true` catalog
|
|
42
|
+
// permission, is governance-owned data in
|
|
43
|
+
// modules/governance/protected-surfaces.json — no longer a constant baked into
|
|
44
|
+
// this file. Re-mapping a floor there is a POLICY edit. It cannot move
|
|
45
|
+
// enforcement into the app: the three layers above (git pre-push hook, grader
|
|
46
|
+
// pre-pass, post-push main audit) plus gate-review.js and the goal-scope check
|
|
47
|
+
// read the registry out of band — no DB, no server, no HTTP — and remain the
|
|
48
|
+
// authority (ADR 0043). Making the request path the enforcer is the exact
|
|
49
|
+
// regression this task exists to prevent.
|
|
50
|
+
//
|
|
51
|
+
// WHY A REPO FILE AND NOT A DB QUERY: the enforcers run where there is no
|
|
52
|
+
// database and no server (a git hook on a laptop, a CI job). The registry's
|
|
53
|
+
// canonical form must therefore be SYNCHRONOUSLY loadable from the checkout. A
|
|
54
|
+
// DB-backed override belongs to the governance tab, layered on top — never a
|
|
55
|
+
// dependency of the hook.
|
|
56
|
+
//
|
|
57
|
+
// WHY `fs` AND NOT `require`: ADR 0083's one-way rule forbids core from
|
|
58
|
+
// require-ing a MODULE's code (a module's behavior + enable/disable state must
|
|
59
|
+
// never be something the kernel depends on), and scripts/gds/fitness.js enforces
|
|
60
|
+
// that on `require` edges. This is not code — it is a static declarative data
|
|
61
|
+
// file that ships inside the core package next to this file (modules/ ships with
|
|
62
|
+
// @bongos/core, ADR 0108 §1). The sibling trust primitive route-rank-check.js
|
|
63
|
+
// already reads modules/*/routes/*.js off disk the same way, to rank-gate them.
|
|
64
|
+
// Code still flows ONE way only: modules/governance/protected-surfaces.js →
|
|
65
|
+
// src/module-api.js → this matcher. Nothing in core requires the module.
|
|
43
66
|
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
'modules/lifecycle/merge-lock.js',
|
|
92
|
-
'modules/lifecycle/ship-preflight.js',
|
|
93
|
-
'modules/lifecycle/github-push.js',
|
|
94
|
-
'modules/lifecycle/conflict-resolve.js',
|
|
95
|
-
'modules/lifecycle/publish-reconciler.js',
|
|
96
|
-
// --- schema: migrations are never newcomer work ---
|
|
97
|
-
'migrations/',
|
|
98
|
-
// --- the deploy substrate ---
|
|
99
|
-
'infra/',
|
|
100
|
-
'.github/', // #863-followup: CI workflows (deploy-prod.yml, grade gate, secrets-scan) are the pipeline
|
|
101
|
-
'CODEOWNERS', // task 1139 (ADR 0058): the code-owner gate list itself
|
|
102
|
-
'config/deploy.json', // task 1139 (ADR 0058): the laptop/ci/bypass deploy switch
|
|
103
|
-
'package.json', // #863-followup: npm scripts + prepare/lifecycle hooks run during install/CI
|
|
104
|
-
'package-lock.json', // task 1143 (ADR 0058): the resolved supply chain npm ci installs on the droplet
|
|
105
|
-
// --- the hooks the gate is DELIVERED through (self-protect Layer 1) ---
|
|
106
|
-
'.husky/', // #863-followup: pre-push (this gate) + pre-commit (secrets guard)
|
|
107
|
-
// --- the trust-boundary documentation + methodology core ---
|
|
108
|
-
'docs/canonical-permissions.md',
|
|
109
|
-
'docs/adr/0016-trust-boundary-server-enforced-permissions.md',
|
|
110
|
-
'docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md', // #863-followup: this fix's own ADR
|
|
111
|
-
'CLAUDE.md',
|
|
112
|
-
// --- local automation that could weaken a gate ---
|
|
113
|
-
'.claude/hooks/',
|
|
114
|
-
'.claude/settings.json',
|
|
115
|
-
];
|
|
67
|
+
// FAIL-CLOSED: a missing/empty/malformed registry THROWS. It never degrades to
|
|
68
|
+
// "nothing is protected" — an unreadable registry is a broken install, not an
|
|
69
|
+
// opted-out module.
|
|
70
|
+
//
|
|
71
|
+
// Resolved from __dirname (this file is <coreRoot>/src/bongos/) rather than via
|
|
72
|
+
// instance-config so the load keeps zero repo imports and works in a bare git
|
|
73
|
+
// hook.
|
|
74
|
+
const REGISTRY_PATH = path.join(__dirname, '..', '..', 'modules', 'governance', 'protected-surfaces.json');
|
|
75
|
+
|
|
76
|
+
function loadRegistry(file) {
|
|
77
|
+
let raw;
|
|
78
|
+
try {
|
|
79
|
+
raw = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
80
|
+
} catch (e) {
|
|
81
|
+
throw new Error(`protected-surface registry unreadable at ${file}: ${e.message}. Refusing to run with an empty protected set (ADR 0043).`);
|
|
82
|
+
}
|
|
83
|
+
const surfaces = Array.isArray(raw && raw.surfaces) ? raw.surfaces : null;
|
|
84
|
+
if (!surfaces || surfaces.length === 0) {
|
|
85
|
+
throw new Error(`protected-surface registry ${file} declares no surfaces. Refusing to run with an empty protected set (ADR 0043).`);
|
|
86
|
+
}
|
|
87
|
+
const defaultFloor = raw.floor;
|
|
88
|
+
const defaultPermission = raw.permission;
|
|
89
|
+
return Object.freeze(surfaces.map((s) => {
|
|
90
|
+
const glob = s && s.glob;
|
|
91
|
+
const floor = (s && s.floor) || defaultFloor;
|
|
92
|
+
const permission = (s && s.permission) || defaultPermission;
|
|
93
|
+
if (typeof glob !== 'string' || !glob) throw new Error(`protected-surface registry ${file}: a surface is missing 'glob'`);
|
|
94
|
+
if (!RANK_TIER[floor]) throw new Error(`protected-surface registry ${file}: surface "${glob}" has an unknown floor "${floor}"`);
|
|
95
|
+
if (typeof permission !== 'string' || !permission) throw new Error(`protected-surface registry ${file}: surface "${glob}" maps to no permission`);
|
|
96
|
+
return Object.freeze({ glob, floor, permission, group: (s && s.group) || null, why: (s && s.why) || null });
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// The registry as loaded: [{ glob, floor, permission, group, why }] in file order.
|
|
101
|
+
const PROTECTED_SURFACES = loadRegistry(REGISTRY_PATH);
|
|
102
|
+
|
|
103
|
+
// The glob list, DERIVED from the registry. Kept as an export because it is the
|
|
104
|
+
// long-standing single source every consumer already reads (module-scope-map,
|
|
105
|
+
// gate-review, publish-manifest, search-ingest-md, sequence) — those keep
|
|
106
|
+
// working unchanged and are now registry-backed by construction.
|
|
107
|
+
const PROTECTED_GLOBS = PROTECTED_SURFACES.map((s) => s.glob);
|
|
108
|
+
|
|
109
|
+
// The floor a builder must clear to touch a protected path, DERIVED from the
|
|
110
|
+
// registry (the lowest floor any surface declares — 'metic' today). Exported
|
|
111
|
+
// because main-audit.js and modules/lifecycle/routes/tasks.js gate on it; the
|
|
112
|
+
// per-surface floor below is what actually decides a hit.
|
|
113
|
+
const MIN_TIER = Math.min(...PROTECTED_SURFACES.map((s) => RANK_TIER[s.floor]));
|
|
116
114
|
|
|
117
115
|
const SPECIALTY =
|
|
118
116
|
'deterministic: a builder below Metic must not modify rank / permission / ship-grade / deploy / migration surfaces (ADR 0016, SEC #863)';
|
|
@@ -142,31 +140,54 @@ function escapeRe(s) {
|
|
|
142
140
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
143
141
|
}
|
|
144
142
|
|
|
145
|
-
const COMPILED =
|
|
143
|
+
const COMPILED = PROTECTED_SURFACES.map((s) => ({ ...s, re: globToRegExp(s.glob) }));
|
|
146
144
|
|
|
147
145
|
// Normalize a path the way git reports it (forward slashes, no leading ./).
|
|
148
146
|
function normalize(p) {
|
|
149
147
|
return String(p || '').replace(/\\/g, '/').replace(/^\.\//, '').trim();
|
|
150
148
|
}
|
|
151
149
|
|
|
152
|
-
// Which of `files` are permission-sensitive? Returns
|
|
150
|
+
// Which of `files` are permission-sensitive? Returns
|
|
151
|
+
// [{ file, glob, floor, permission }] — floor + permission come straight from the
|
|
152
|
+
// registry entry that matched, so a governance re-map flows through every caller.
|
|
153
153
|
function matchProtected(files) {
|
|
154
154
|
const out = [];
|
|
155
155
|
for (const raw of files || []) {
|
|
156
156
|
const f = normalize(raw);
|
|
157
157
|
if (!f) continue;
|
|
158
158
|
const hit = COMPILED.find((c) => c.re.test(f));
|
|
159
|
-
if (hit) out.push({ file: f, glob: hit.glob });
|
|
159
|
+
if (hit) out.push({ file: f, glob: hit.glob, floor: hit.floor, permission: hit.permission });
|
|
160
160
|
}
|
|
161
161
|
return out;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
// The registry entry governing `file`, or null when the path is unprotected.
|
|
165
|
+
function surfaceFor(file) {
|
|
166
|
+
const f = normalize(file);
|
|
167
|
+
const hit = f ? COMPILED.find((c) => c.re.test(f)) : null;
|
|
168
|
+
return hit ? { glob: hit.glob, floor: hit.floor, permission: hit.permission, group: hit.group, why: hit.why } : null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// The rank floor governing `file` ('metic' today), or null when unprotected.
|
|
172
|
+
function floorFor(file) {
|
|
173
|
+
const s = surfaceFor(file);
|
|
174
|
+
return s ? s.floor : null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// The system:true catalog permission `file` maps to, or null when unprotected.
|
|
178
|
+
function permissionFor(file) {
|
|
179
|
+
const s = surfaceFor(file);
|
|
180
|
+
return s ? s.permission : null;
|
|
181
|
+
}
|
|
182
|
+
|
|
164
183
|
function tierOf(rank) {
|
|
165
184
|
return RANK_TIER[rank] ?? null; // null = unknown rank
|
|
166
185
|
}
|
|
167
186
|
|
|
168
|
-
// Is this rank below the protected-path floor?
|
|
169
|
-
//
|
|
187
|
+
// Is this rank below the registry's LOWEST protected-path floor? A coarse
|
|
188
|
+
// "could this rank be blocked by anything at all" test — main-audit.js uses it
|
|
189
|
+
// after matchProtected has already established a hit. Unknown ranks are treated
|
|
190
|
+
// as NOT-below here (no finding) — see checkPermissionPaths for why unknown must
|
|
170
191
|
// fail OPEN at the grader layer (the authoritative audit, layer 3, owns the
|
|
171
192
|
// unknown/dishonest case and reads the real rank from the DB).
|
|
172
193
|
function isBelowFloor(rank) {
|
|
@@ -184,21 +205,26 @@ function isBelowFloor(rank) {
|
|
|
184
205
|
// the layer that fails-closed on the dishonest path.
|
|
185
206
|
function checkPermissionPaths({ changedFiles, builderRank } = {}) {
|
|
186
207
|
const protectedHits = matchProtected(changedFiles);
|
|
187
|
-
const
|
|
208
|
+
const tier = tierOf(builderRank);
|
|
188
209
|
const findings = [];
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
210
|
+
for (const h of protectedHits) {
|
|
211
|
+
// Decided against the hit's OWN registry floor, not a global constant — that
|
|
212
|
+
// is what makes "the governance tab can re-map the floor" real. Every surface
|
|
213
|
+
// floors at 'metic' today, so this is identical to the previous global test.
|
|
214
|
+
if (tier === null || tier >= RANK_TIER[h.floor]) continue;
|
|
215
|
+
const floorLabel = h.floor.charAt(0).toUpperCase() + h.floor.slice(1);
|
|
216
|
+
findings.push({
|
|
217
|
+
severity: 'blocker',
|
|
218
|
+
file: h.file,
|
|
219
|
+
glob: h.glob,
|
|
220
|
+
floor: h.floor,
|
|
221
|
+
permission: h.permission,
|
|
222
|
+
summary:
|
|
223
|
+
`${h.file} is a permission-sensitive surface (matches \`${h.glob}\`). `
|
|
224
|
+
+ `Builder rank '${builderRank}' is below ${floorLabel} and may not modify the rank / permission / `
|
|
225
|
+
+ `ship-grade / deploy / migration machinery (ADR 0016, SEC #863). `
|
|
226
|
+
+ `If this change is genuinely needed, an Archon must own it.`,
|
|
227
|
+
});
|
|
202
228
|
}
|
|
203
229
|
return {
|
|
204
230
|
ok: findings.length === 0,
|
|
@@ -215,8 +241,11 @@ function checkPermissionPaths({ changedFiles, builderRank } = {}) {
|
|
|
215
241
|
function toWorkerResult(result) {
|
|
216
242
|
const verdict = result.hardFail ? 'fail' : 'pass';
|
|
217
243
|
const n = result.findings.length;
|
|
244
|
+
// Floor label comes from the findings (registry data), not a hardcoded 'Metic'.
|
|
245
|
+
const floor = n > 0 ? result.findings[0].floor : null;
|
|
246
|
+
const floorLabel = floor ? floor.charAt(0).toUpperCase() + floor.slice(1) : 'the floor';
|
|
218
247
|
const header = verdict === 'fail'
|
|
219
|
-
? `Permission-Path — FAIL (rank '${result.builderRank}' below
|
|
248
|
+
? `Permission-Path — FAIL (rank '${result.builderRank}' below ${floorLabel} touched ${n} protected path(s))`
|
|
220
249
|
: `Permission-Path — PASS`;
|
|
221
250
|
const body = result.findings.map((f) => ` [${f.severity}] ${f.file} — ${f.summary}`).join('\n');
|
|
222
251
|
return {
|
|
@@ -238,9 +267,14 @@ module.exports = {
|
|
|
238
267
|
RANK_TIER,
|
|
239
268
|
MIN_TIER,
|
|
240
269
|
PROTECTED_GLOBS,
|
|
270
|
+
PROTECTED_SURFACES,
|
|
271
|
+
REGISTRY_PATH,
|
|
241
272
|
SPECIALTY,
|
|
242
273
|
globToRegExp,
|
|
243
274
|
matchProtected,
|
|
275
|
+
surfaceFor,
|
|
276
|
+
floorFor,
|
|
277
|
+
permissionFor,
|
|
244
278
|
tierOf,
|
|
245
279
|
isBelowFloor,
|
|
246
280
|
checkPermissionPaths,
|
package/src/bongos/repo-info.js
CHANGED
|
@@ -44,26 +44,61 @@ function loadFromEnv() {
|
|
|
44
44
|
return null;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
// The directory this file's package occupies: <root>/src/bongos -> <root>. In the core
|
|
48
|
+
// dev checkout that is the repo root; installed, it is node_modules/@bongos/core.
|
|
49
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
|
|
50
|
+
|
|
51
|
+
// Same directory? Normalizes separator style (git prints POSIX separators even on
|
|
52
|
+
// Windows) and surrounding whitespace, and matches the platform's case rules.
|
|
53
|
+
function sameDir(a, b) {
|
|
54
|
+
if (!a || !b) return false;
|
|
55
|
+
const norm = (p) => {
|
|
56
|
+
const abs = path.resolve(String(p).trim());
|
|
57
|
+
return process.platform === 'win32' ? abs.toLowerCase() : abs;
|
|
58
|
+
};
|
|
59
|
+
return norm(a) === norm(b);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Resolve the remote ONLY when this package IS the git repo, never a repo found by
|
|
63
|
+
// walking up out of it.
|
|
64
|
+
//
|
|
65
|
+
// git discovery searches ANCESTORS of cwd. In the core dev checkout PACKAGE_ROOT is the
|
|
66
|
+
// repo root, so `git remote get-url origin` answers correctly. But on a live instance
|
|
67
|
+
// (ADR 0140) the hub runs from node_modules/@bongos/core, which is not a repo — so git
|
|
68
|
+
// climbed out of the package, found the enclosing INSTANCE repo, and returned its origin.
|
|
69
|
+
// That silently bound a DIFFERENT repo than the one the core publishes to, so every
|
|
70
|
+
// publish call 404'd against a repo the builder had no access to.
|
|
71
|
+
//
|
|
72
|
+
// Anchor the answer: ask git for its toplevel first and require it to EQUAL the directory
|
|
73
|
+
// we probed. If it differs, the repo is someone else's — return null so loadRepoInfo falls
|
|
74
|
+
// through to the env pin (<PREFIX>_GITHUB_OWNER/_REPO) or to an explicit no_repo_info. An
|
|
75
|
+
// error is strictly better than a wrong answer here: a misbind produces confident 404s
|
|
76
|
+
// that are hard to trace, while the error is printed verbatim by the publish-reconciler's
|
|
77
|
+
// boot line and names its own cure.
|
|
78
|
+
function loadFromGit(deps = {}) {
|
|
79
|
+
const exec = deps.execSync || execSync;
|
|
80
|
+
const root = deps.packageRoot || PACKAGE_ROOT;
|
|
81
|
+
const opts = { cwd: root, encoding: 'utf8', timeout: 2000, stdio: ['ignore', 'pipe', 'pipe'] };
|
|
48
82
|
try {
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
timeout: 2000,
|
|
53
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
54
|
-
});
|
|
55
|
-
return parseRemote(remote);
|
|
83
|
+
const toplevel = exec('git rev-parse --show-toplevel', opts);
|
|
84
|
+
if (!sameDir(toplevel, root)) return null;
|
|
85
|
+
return parseRemote(exec('git remote get-url origin', opts));
|
|
56
86
|
} catch (_) {
|
|
57
87
|
return null;
|
|
58
88
|
}
|
|
59
89
|
}
|
|
60
90
|
|
|
61
|
-
|
|
91
|
+
// `deps` is the test seam (execSync / packageRoot); production calls this with no args.
|
|
92
|
+
function loadRepoInfo(deps = {}) {
|
|
62
93
|
if (cached) return cached;
|
|
63
94
|
const branch = ic.resolveEnv('GITHUB_BRANCH') || 'main';
|
|
64
|
-
const parsed = loadFromEnv() || loadFromGit();
|
|
95
|
+
const parsed = loadFromEnv() || loadFromGit(deps);
|
|
65
96
|
if (!parsed) {
|
|
66
|
-
cached = {
|
|
97
|
+
cached = {
|
|
98
|
+
error: 'no_repo_info',
|
|
99
|
+
detail:
|
|
100
|
+
'git remote origin not resolvable from this package (an installed core does not sit inside the repo it publishes to) and <PREFIX>_GITHUB_OWNER/REPO unset',
|
|
101
|
+
};
|
|
67
102
|
return cached;
|
|
68
103
|
}
|
|
69
104
|
const base = `https://github.com/${parsed.owner}/${parsed.repo}`;
|
|
@@ -87,5 +122,6 @@ function _resetCacheForTests() {
|
|
|
87
122
|
module.exports = {
|
|
88
123
|
loadRepoInfo,
|
|
89
124
|
parseRemote,
|
|
125
|
+
loadFromGit, // exported for unit tests — the anchor rule is the whole fix
|
|
90
126
|
_resetCacheForTests,
|
|
91
127
|
};
|