@bongos/core 1.19.804 → 1.19.805
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 +257 -237
- package/.claude/skills/ask-for-help/SKILL.md +6 -6
- package/.claude/skills/backlog-review/SKILL.md +1 -1
- package/.claude/skills/blocker-review/SKILL.md +7 -7
- package/.claude/skills/blocker-solve/SKILL.md +5 -5
- package/.claude/skills/bug-triage/SKILL.md +7 -7
- package/.claude/skills/builder-claim/SKILL.md +3 -3
- package/.claude/skills/builder-cost/SKILL.md +2 -2
- package/.claude/skills/builder-end/SKILL.md +2 -2
- package/.claude/skills/builder-exit/SKILL.md +7 -7
- package/.claude/skills/builder-key/SKILL.md +2 -2
- package/.claude/skills/builder-reauth/SKILL.md +2 -2
- package/.claude/skills/builder-redteam/SKILL.md +7 -7
- package/.claude/skills/builder-release/SKILL.md +2 -2
- package/.claude/skills/builder-sequence/SKILL.md +1 -1
- package/.claude/skills/builder-setup/SKILL.md +3 -3
- package/.claude/skills/builder-ship/SKILL.md +1 -1
- package/.claude/skills/builder-stage/SKILL.md +1 -1
- package/.claude/skills/builder-start/SKILL.md +1 -1
- package/.claude/skills/fix-task/SKILL.md +4 -4
- package/.claude/skills/goal-create/SKILL.md +18 -18
- package/.claude/skills/goal-review/SKILL.md +7 -7
- package/.claude/skills/grade-audit/SKILL.md +5 -5
- package/.claude/skills/grade-recover/SKILL.md +4 -4
- package/.claude/skills/grader-health/SKILL.md +6 -6
- package/.claude/skills/idea-triage/SKILL.md +14 -14
- package/.claude/skills/merge-mode/SKILL.md +3 -3
- package/.claude/skills/planning-session/SKILL.md +20 -20
- package/.claude/skills/priority-session/SKILL.md +10 -10
- package/.claude/skills/recall/SKILL.md +1 -1
- package/.claude/skills/scan-before-install/SKILL.md +3 -3
- package/.claude/skills/status/SKILL.md +2 -2
- package/.claude/skills/strand-fix/SKILL.md +2 -2
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +2 -0
- package/clients/bongos-client/index.cjs +2 -0
- package/clients/bongos-client/index.d.ts +2 -0
- package/clients/bongos-client/index.mjs +2 -0
- package/docs/api/openapi.json +45 -11
- package/docs/api-reference.md +11 -10
- package/docs/module-api-changelog.md +2 -0
- package/modules/builder-settings/profile-nudge-prefs.js +1 -1
- package/modules/builder-settings/render-prefs.js +1 -1
- package/modules/dev-box/app/README.md +1 -1
- package/modules/dev-box/app/src/gds-client.js +11 -9
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +2 -0
- package/modules/dev-box/app/test/unit.mjs +13 -13
- package/modules/dev-box/box-access.js +3 -3
- package/modules/dev-box/box-onboard.js +7 -7
- package/modules/discord/bug-attachments.js +1 -1
- package/modules/economy/cost-classify.js +6 -6
- package/modules/grading/grader-rubric.json +1 -1
- package/modules/grading/grader-score.js +1 -1
- package/modules/hall-ui/module.json +1 -1
- package/modules/hall-ui/public/drachmae.js +3 -3
- package/modules/hall-ui/public/idea.js +1 -1
- package/modules/hall-ui/public/md-reader.js +1 -1
- package/modules/hall-ui/public/people.html +1 -1
- package/modules/hall-ui/public/people.js +2 -2
- package/modules/hall-ui/public/primer.js +4 -4
- package/modules/hall-ui/public/roster.js +1 -1
- package/modules/hall-ui/public/shell.js +1 -1
- package/modules/hall-ui/public/task.js +1 -1
- package/modules/ideas/inbox.js +2 -2
- package/modules/lifecycle/db-analytics.js +1 -1
- package/modules/lifecycle/done-when.js +4 -4
- package/modules/lifecycle/version-close.js +1 -1
- package/modules/memory/learnings.js +2 -2
- package/modules/memory/memory.js +1 -1
- package/modules/onboarding/onboarding.js +1 -1
- package/modules/platform-identity/routes/my-projects.js +1 -1
- package/modules/platform-identity/routes/sso.js +2 -2
- package/modules/public-landing/public/index.html +2 -2
- package/modules/public-landing/public/projects-floor.states.json +1 -1
- package/modules/public-landing/public/projects.html +1 -1
- package/modules/public-landing/public/projects.states.json +1 -1
- package/modules/sessions/db.js +120 -0
- package/modules/sessions/module.json +2 -2
- package/modules/sessions/pollers/session-upload-health.js +111 -0
- package/modules/sessions/pulse.js +2 -2
- package/modules/sessions/routes/sessions.js +46 -0
- package/modules/sessions/upload-health.js +197 -0
- package/modules/status-ui/module.json +1 -1
- package/modules/status-ui/public/explore.js +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/agent-invoke.js +3 -3
- package/scripts/gds/api.js +4 -4
- package/scripts/gds/api.sh +1 -1
- package/scripts/gds/architect-audit.js +1 -1
- package/scripts/gds/artifact-audit.js +2 -2
- package/scripts/gds/audit-ships.js +2 -2
- package/scripts/gds/backfill-cost.js +1 -1
- package/scripts/gds/backfill-sessions.js +1 -1
- package/scripts/gds/backfill-subagent-rewards.js +1 -1
- package/scripts/gds/backfill-task-rewards.js +2 -2
- package/scripts/gds/box-auth-check.js +1 -1
- package/scripts/gds/box-sync.js +3 -3
- package/scripts/gds/box.js +10 -10
- package/scripts/gds/build-cli-package.js +3 -3
- package/scripts/gds/capture.js +2 -2
- package/scripts/gds/ci-grade.js +1 -1
- package/scripts/gds/claim-recall.js +2 -2
- package/scripts/gds/cli-lib.js +3 -3
- package/scripts/gds/context-pack.js +1 -1
- package/scripts/gds/copy-apply.js +2 -2
- package/scripts/gds/dev-lib.js +2 -2
- package/scripts/gds/fetch-art-key.js +2 -2
- package/scripts/gds/fetch-sound-prefs.js +3 -3
- package/scripts/gds/grade-smoke.js +1 -1
- package/scripts/gds/hooks/pre-push.js +1 -1
- package/scripts/gds/init.js +9 -9
- package/scripts/gds/key-card.js +1 -1
- package/scripts/gds/learning-capture.js +2 -2
- package/scripts/gds/linkify-refs.js +2 -2
- package/scripts/gds/local-preview-lib.js +1 -1
- package/scripts/gds/login.js +11 -10
- package/scripts/gds/main-audit.js +1 -1
- package/scripts/gds/newcomer-floor.config.json +1 -1
- package/scripts/gds/newcomer-floor.js +2 -2
- package/scripts/gds/newcomer-floor.templates.json +2 -2
- package/scripts/gds/onboarding-ship.js +1 -1
- package/scripts/gds/paste-token.js +3 -3
- package/scripts/gds/portability-smoke-memory.sh +5 -5
- package/scripts/gds/prove-strict-versioning.js +2 -2
- package/scripts/gds/provision-net.js +2 -2
- package/scripts/gds/provision-units.js +3 -3
- package/scripts/gds/pulse.js +2 -2
- package/scripts/gds/push-path-brief.js +2 -2
- package/scripts/gds/reauth.js +1 -1
- package/scripts/gds/recall.js +1 -1
- package/scripts/gds/redteam-patrol.js +3 -3
- package/scripts/gds/render-ideas.js +5 -5
- package/scripts/gds/repo-metrics.js +1 -1
- package/scripts/gds/sandbox-stage.js +3 -3
- package/scripts/gds/seed-adopt-tasks.js +3 -3
- package/scripts/gds/seed-board-room-tasks.js +1 -1
- package/scripts/gds/seed-bongos-app-tasks.js +2 -2
- package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +3 -3
- package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +4 -4
- package/scripts/gds/seed-bongos-tasks.js +5 -5
- package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +1 -1
- package/scripts/gds/seed-bongos-v1-seo-tasks.js +1 -1
- package/scripts/gds/seed-bv1-community-tasks.js +1 -1
- package/scripts/gds/seed-bv1-privacy-invites-tasks.js +1 -1
- package/scripts/gds/seed-bv1-profile-page-tasks.js +1 -1
- package/scripts/gds/seed-bv1-profiles-tasks.js +1 -1
- package/scripts/gds/seed-bv1-r01-delta-tasks.js +1 -1
- package/scripts/gds/seed-gds-v4-tasks.js +3 -3
- package/scripts/gds/seed-medusa-tasks.js +1 -1
- package/scripts/gds/seed-productization-tasks.js +1 -1
- package/scripts/gds/seed-project-admin-console-tasks.js +1 -1
- package/scripts/gds/seed-provisioning-tasks.js +2 -2
- package/scripts/gds/seed-strict-versioning-tasks.js +3 -3
- package/scripts/gds/seed-v2-world-tasks.js +2 -2
- package/scripts/gds/seed-verify-criteria.js +1 -1
- package/scripts/gds/session-digest.js +1 -1
- package/scripts/gds/session.js +2 -2
- package/scripts/gds/setup.js +7 -7
- package/scripts/gds/ship-flow.js +3 -3
- package/scripts/gds/ship-grade-steps.js +3 -3
- package/scripts/gds/ship-memory-sync.js +1 -1
- package/scripts/gds/ship-session-upload.js +3 -3
- package/scripts/gds/smoke-batch-claim.sh +10 -10
- package/scripts/gds/smoke-batch-release.sh +14 -14
- package/scripts/gds/smoke-claim-consistency.sh +19 -19
- package/scripts/gds/smoke-dependencies.sh +9 -9
- package/scripts/gds/smoke-write.sh +11 -11
- package/scripts/gds/start.js +1 -1
- package/scripts/gds/status.js +2 -2
- package/scripts/gds/strand-watch.js +1 -1
- package/scripts/gds/triage.js +4 -4
- package/scripts/gds/version-close.js +2 -2
- package/scripts/hall-preview/README.md +1 -1
- package/scripts/hall-preview/server.js +1 -1
- package/src/bongos/auth-admission.js +3 -3
- package/src/bongos/auth-idp.js +2 -2
- package/src/bongos/auth.js +3 -3
- package/src/bongos/db.js +2 -2
- package/src/bongos/llm-cache.js +2 -2
- package/src/bongos/metrics.js +1 -1
- package/src/bongos/middleware/audit.js +3 -3
- package/src/bongos/middleware/rate-limit.js +1 -1
- package/src/bongos/platform-visibility-gate.js +2 -2
- package/src/bongos/routes/_helpers.js +1 -1
- package/src/bongos/routes/audit-log.js +1 -1
- package/src/bongos/routes/auth.js +5 -5
- package/src/bongos/routes/backup.js +1 -1
- package/src/bongos/routes/builders.js +1 -1
- package/src/bongos/routes/instance.js +1 -1
- package/src/bongos/routes/live.js +1 -1
- package/src/bongos/routes/me.js +2 -2
- package/src/bongos/routes/modules.js +2 -2
- package/src/bongos/routes/public.js +1 -1
- package/src/bongos/routes/security.js +4 -4
- package/src/bongos/routes.js +1 -1
- package/src/bongos/serve-internal.js +6 -6
- package/src/branding.js +1 -1
- package/src/module-api.js +1 -1
- package/src/module-seams.js +2 -2
- package/src/platform-server.js +2 -2
- package/tests/api_alias_exceptions.mjs +67 -0
- package/tests/application_echo.mjs +12 -12
- package/tests/artifact_audit.mjs +1 -1
- package/tests/auth_page_gate.mjs +4 -4
- package/tests/auth_web_recovery.mjs +11 -11
- package/tests/bongos_login.mjs +7 -4
- package/tests/box_env.mjs +6 -6
- package/tests/bug_attachments.mjs +1 -1
- package/tests/cli_sessions.mjs +1 -1
- package/tests/dev_lib.mjs +1 -1
- package/tests/discord_bugs.mjs +2 -2
- package/tests/discord_inbound.mjs +2 -2
- package/tests/explore_visible_states.mjs +1 -1
- package/tests/government_page_gates.mjs +1 -1
- package/tests/hall_reference_world.mjs +1 -1
- package/tests/idea_ideate_full.mjs +1 -1
- package/tests/idp_federation.mjs +2 -2
- package/tests/llm-cache.mjs +1 -1
- package/tests/manage_manifest_shared_read.mjs +3 -3
- package/tests/people_directory_clip.mjs +1 -1
- package/tests/planning_session_skill.mjs +1 -1
- package/tests/platform_visibility_gate.mjs +15 -15
- package/tests/profile_route.mjs +25 -25
- package/tests/projects_hub.mjs +2 -2
- package/tests/provision.mjs +2 -2
- package/tests/provision_settings_apply.mjs +4 -4
- package/tests/sandbox_stage.mjs +8 -8
- package/tests/scouting_owner_access_and_reach.mjs +3 -3
- package/tests/session_upload_health.mjs +329 -0
- package/tests/setup_device_flow_fallback.mjs +1 -1
- package/tests/skill_ask_for_help.mjs +3 -3
- package/tests/skill_grade_audit.mjs +2 -2
- package/tests/skill_grader_health.mjs +3 -3
- package/tests/smoke_write_contract.mjs +1 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// tests/api_alias_exceptions.mjs — the callers task 1003707 deliberately LEFT on
|
|
2
|
+
// the permanent /api/gds alias, and the reason each one stays.
|
|
3
|
+
//
|
|
4
|
+
// WHY THIS FILE EXISTS. C3e moved every in-repo caller onto the canonical
|
|
5
|
+
// /api/bongos. A handful were held back on purpose, and "on purpose" is the kind
|
|
6
|
+
// of fact that survives exactly one sweep: the next agent greps for the old
|
|
7
|
+
// spelling, sees four stragglers, tidies them, and discovers what they were for
|
|
8
|
+
// when sign-in breaks. Each case below names its reason, so a future move has to
|
|
9
|
+
// argue with the reason rather than with a leftover.
|
|
10
|
+
//
|
|
11
|
+
// The mount itself is asserted by tests/rename_history_restraint.mjs (structure)
|
|
12
|
+
// and tests/api_path_404.mjs (dispatch — the alias is a live mount, so it gets no
|
|
13
|
+
// corrective 404 hint). Only the ONE line that makes the alias permanent is
|
|
14
|
+
// re-asserted here, because these exceptions are worthless without it.
|
|
15
|
+
import assert from 'node:assert/strict';
|
|
16
|
+
import { test } from 'node:test';
|
|
17
|
+
import fs from 'node:fs';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import { createRequire } from 'node:module';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
24
|
+
const read = (rel) => fs.readFileSync(path.join(ROOT, rel), 'utf8');
|
|
25
|
+
const ALIAS = '/api/gds';
|
|
26
|
+
|
|
27
|
+
test('the alias is still mounted — everything below depends on it', () => {
|
|
28
|
+
const { API_PREFIX, LEGACY_API_PREFIXES, ALL_API_PREFIXES } = require(path.join(ROOT, 'src', 'bongos', 'api-prefix.js'));
|
|
29
|
+
assert.equal(API_PREFIX, '/api/bongos', 'the canonical prefix is what in-repo callers now ask for');
|
|
30
|
+
assert.ok(LEGACY_API_PREFIXES.includes(ALIAS), 'shipped Dev Box binaries and live dev boxes call the alias');
|
|
31
|
+
assert.ok(ALL_API_PREFIXES.includes(ALIAS), 'and the router still mounts it');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('the OAuth callbacks stay on the alias — they are registered outside this repo', () => {
|
|
35
|
+
const auth = read('src/bongos/routes/auth.js');
|
|
36
|
+
// Changing either of these needs a matching edit in the GitHub / Discord app
|
|
37
|
+
// settings; a repo-only change silently breaks sign-in. Pin the lines that BUILD
|
|
38
|
+
// the redirect_uri, not a mention of the path — auth.js also names it in an error
|
|
39
|
+
// message, and matching that would keep this green with both builders rewritten.
|
|
40
|
+
const webBuilders = auth.split(`\${WEB_REDIRECT_ORIGIN}${ALIAS}/auth/web/callback`).length - 1;
|
|
41
|
+
assert.equal(webBuilders, 2, 'both GitHub redirect_uri builders stay on the alias (auth.js WEB_REDIRECT_ORIGIN)');
|
|
42
|
+
assert.ok(auth.includes(`\${DISCORD_REDIRECT_ORIGIN}${ALIAS}/auth/discord/callback`),
|
|
43
|
+
'Discord OAuth app callback (DISCORD_REDIRECT_URI)');
|
|
44
|
+
// The instance provisioner registers the same pinned path for every new instance.
|
|
45
|
+
assert.ok(read('modules/provisioning/provisioning.js').includes(`${ALIAS}/auth/web/callback`),
|
|
46
|
+
'a provisioned instance registers the pinned callback, not the canonical one');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('the sign-in START href moved, and that is safe because the cookie is path-scoped to /', () => {
|
|
50
|
+
const auth = read('src/bongos/routes/auth.js');
|
|
51
|
+
assert.ok(auth.includes('/api/bongos/auth/web/start'), 'the start link asks for the canonical path');
|
|
52
|
+
assert.ok(/path: '\/'/.test(auth), 'the session cookie is set at path / — it reaches BOTH prefixes');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('the uptime poller stays on the alias so production keeps exercising it', () => {
|
|
56
|
+
// If nothing in production ever calls the alias, its eventual breakage is
|
|
57
|
+
// discovered by a user rather than by us.
|
|
58
|
+
assert.ok(read('src/bongos/uptime-poller.js').includes(`${ALIAS}/healthz`),
|
|
59
|
+
'the poller is the one live caller that proves the alias answers');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('a pasted API base is stripped whichever spelling it carries', () => {
|
|
63
|
+
const { normalizeInstanceBase } = require(path.join(ROOT, 'scripts', 'gds', 'login.js'));
|
|
64
|
+
for (const suffix of ['/api/bongos', '/api/bongos/v1', '/api/gds', '/api/gds/']) {
|
|
65
|
+
assert.equal(normalizeInstanceBase(`https://example.com${suffix}`), 'https://example.com', suffix);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
@@ -274,7 +274,7 @@ const { attachFail } = require('../src/bongos/middleware/error-envelope.js');
|
|
|
274
274
|
let relay = { status: 201, body: { ok: true } };
|
|
275
275
|
const realFetch = globalThis.fetch;
|
|
276
276
|
globalThis.fetch = async (url) => {
|
|
277
|
-
if (String(url).endsWith('/api/
|
|
277
|
+
if (String(url).endsWith('/api/bongos/access-requests')) {
|
|
278
278
|
if (relay === null) throw new Error('connection refused');
|
|
279
279
|
return { status: relay.status, json: async () => relay.body };
|
|
280
280
|
}
|
|
@@ -285,7 +285,7 @@ after(() => { globalThis.fetch = realFetch; });
|
|
|
285
285
|
const app = express();
|
|
286
286
|
app.use(express.json());
|
|
287
287
|
app.use(attachFail);
|
|
288
|
-
app.use('/api/
|
|
288
|
+
app.use('/api/bongos', myProjectsRoutes());
|
|
289
289
|
|
|
290
290
|
let server, port;
|
|
291
291
|
before(async () => {
|
|
@@ -314,7 +314,7 @@ function call(method, pathname, body) {
|
|
|
314
314
|
req.end(payload);
|
|
315
315
|
});
|
|
316
316
|
}
|
|
317
|
-
const join = (note) => call('POST', '/api/
|
|
317
|
+
const join = (note) => call('POST', '/api/bongos/my-projects/join', { origin: 'https://target.example', note });
|
|
318
318
|
|
|
319
319
|
test('the interpreter refuses a predicate it cannot read — parameterised or not', () => {
|
|
320
320
|
assert.throws(() => predicateFor('github_id = $1::bigint AND something = $2', [1, 2]), /unread predicate on \$2/);
|
|
@@ -391,7 +391,7 @@ test('a failed echo write never turns a filed application into a reported failur
|
|
|
391
391
|
test('GET /my-projects reports what was applied to and when — and no status', async () => {
|
|
392
392
|
seed();
|
|
393
393
|
relay = { status: 201, body: { ok: true } };
|
|
394
|
-
const r = await call('GET', '/api/
|
|
394
|
+
const r = await call('GET', '/api/bongos/my-projects');
|
|
395
395
|
assert.equal(r.status, 200);
|
|
396
396
|
const applied = r.json.applied;
|
|
397
397
|
assert.deepEqual(applied.map((a) => a.client_id), ['proj-open', 'proj-invited'],
|
|
@@ -405,7 +405,7 @@ test('GET /my-projects reports what was applied to and when — and no status',
|
|
|
405
405
|
|
|
406
406
|
test('a project the applicant now BUILDS on drops out of applied — membership is the approval signal', async () => {
|
|
407
407
|
seed();
|
|
408
|
-
const r = await call('GET', '/api/
|
|
408
|
+
const r = await call('GET', '/api/bongos/my-projects');
|
|
409
409
|
assert.deepEqual(r.json.building.map((b) => b.client_id), ['proj-joined']);
|
|
410
410
|
assert.ok(!r.json.applied.some((a) => a.client_id === 'proj-joined'),
|
|
411
411
|
'an approval becomes visible by the card flipping to member, never by the echo claiming it');
|
|
@@ -421,7 +421,7 @@ test('a project the applicant now BUILDS on drops out of applied — membership
|
|
|
421
421
|
|
|
422
422
|
test('an echo older than the window is invisible, not deleted', async () => {
|
|
423
423
|
seed();
|
|
424
|
-
const r = await call('GET', '/api/
|
|
424
|
+
const r = await call('GET', '/api/bongos/my-projects');
|
|
425
425
|
assert.ok(!r.json.applied.some((a) => a.client_id === 'proj-stale'),
|
|
426
426
|
'a declined application must not read as "applied" forever');
|
|
427
427
|
assert.ok(echoes.some((e) => e.client_id === 'proj-stale'), 'and the row is still there — the window is read-time');
|
|
@@ -429,7 +429,7 @@ test('an echo older than the window is invisible, not deleted', async () => {
|
|
|
429
429
|
|
|
430
430
|
test('the echo read is own-scope: another account’s row is never reachable', async () => {
|
|
431
431
|
seed();
|
|
432
|
-
const r = await call('GET', '/api/
|
|
432
|
+
const r = await call('GET', '/api/bongos/my-projects');
|
|
433
433
|
assert.ok(!r.json.applied.some((a) => a.client_id === 'proj-someone-elses'));
|
|
434
434
|
const echoRead = statements.find((s) => /FROM platform_identity_application_echoes/.test(s.sql));
|
|
435
435
|
assert.match(echoRead.sql, /WHERE e\.github_id = \$1::bigint/, 'keyed on the session, never on anything from the request');
|
|
@@ -444,12 +444,12 @@ test('the echo read is own-scope: another account’s row is never reachable', a
|
|
|
444
444
|
test('leaving a project forgets the application that got you in', async () => {
|
|
445
445
|
seed();
|
|
446
446
|
assert.ok(echo('proj-joined'), 'precondition: the echo from the original application is still on file');
|
|
447
|
-
const left = await call('POST', '/api/
|
|
447
|
+
const left = await call('POST', '/api/bongos/my-projects/proj-joined/leave');
|
|
448
448
|
assert.equal(left.status, 200);
|
|
449
449
|
assert.equal(left.json.left, true);
|
|
450
450
|
assert.equal(echo('proj-joined'), undefined, 'the echo goes with the membership');
|
|
451
451
|
|
|
452
|
-
const after = await call('GET', '/api/
|
|
452
|
+
const after = await call('GET', '/api/bongos/my-projects');
|
|
453
453
|
assert.ok(!after.json.building.some((b) => b.client_id === 'proj-joined'));
|
|
454
454
|
assert.ok(!after.json.applied.some((a) => a.client_id === 'proj-joined'),
|
|
455
455
|
'and it does NOT come back as "applied" now that the membership no longer hides it');
|
|
@@ -457,7 +457,7 @@ test('leaving a project forgets the application that got you in', async () => {
|
|
|
457
457
|
|
|
458
458
|
test('leaving forgets only the leaver’s own echo, for only that project', async () => {
|
|
459
459
|
seed();
|
|
460
|
-
await call('POST', '/api/
|
|
460
|
+
await call('POST', '/api/bongos/my-projects/proj-joined/leave');
|
|
461
461
|
assert.ok(echo('proj-open'), 'a different project of mine is untouched');
|
|
462
462
|
assert.ok(echoes.some((e) => e.client_id === 'proj-someone-elses'), 'and so is another account’s row');
|
|
463
463
|
});
|
|
@@ -465,7 +465,7 @@ test('leaving forgets only the leaver’s own echo, for only that project', asyn
|
|
|
465
465
|
test('a failed echo cleanup does not fail a leave that already happened', async () => {
|
|
466
466
|
seed();
|
|
467
467
|
echoFails = true;
|
|
468
|
-
const left = await call('POST', '/api/
|
|
468
|
+
const left = await call('POST', '/api/bongos/my-projects/proj-joined/leave');
|
|
469
469
|
assert.equal(left.status, 200, 'the membership is already gone — the echo is a convenience, not the act');
|
|
470
470
|
assert.equal(left.json.left, true);
|
|
471
471
|
});
|
|
@@ -473,7 +473,7 @@ test('a failed echo cleanup does not fail a leave that already happened', async
|
|
|
473
473
|
test('a failed echo read costs the applied list and nothing else', async () => {
|
|
474
474
|
seed();
|
|
475
475
|
echoFails = true;
|
|
476
|
-
const r = await call('GET', '/api/
|
|
476
|
+
const r = await call('GET', '/api/bongos/my-projects');
|
|
477
477
|
assert.equal(r.status, 200);
|
|
478
478
|
assert.deepEqual(r.json.applied, []);
|
|
479
479
|
assert.deepEqual(r.json.building.map((b) => b.client_id), ['proj-joined'], 'the memberships listing still lands');
|
package/tests/artifact_audit.mjs
CHANGED
|
@@ -171,7 +171,7 @@ await t('a finding is filed to the blocker surface, not only printed', async ()
|
|
|
171
171
|
const call = async (method, path, body) => { sent.push({ method, path, body }); return { ok: true, status: 201, data: { blocker: { id: 42 } } }; };
|
|
172
172
|
const r = await fileBlocker([{ id: '1003188', status: 'shipped', shipped_at: '2026-08-23', title: 'Go-live', touches: ['package.json'] }], { call });
|
|
173
173
|
assert.equal(r.filed, true);
|
|
174
|
-
assert.equal(sent[0].path, '/api/
|
|
174
|
+
assert.equal(sent[0].path, '/api/bongos/blockers');
|
|
175
175
|
assert.equal(sent[0].body.source, 'artifact-audit');
|
|
176
176
|
assert.match(sent[0].body.body_md, /task 1003188/);
|
|
177
177
|
});
|
package/tests/auth_page_gate.mjs
CHANGED
|
@@ -74,7 +74,7 @@ await t('unauthenticated request → 302 to sign-in, next() NOT called', async (
|
|
|
74
74
|
assert.equal(nexted, false, 'next() must not run for an unauthenticated request');
|
|
75
75
|
assert.ok(res._redirect, 'a redirect must be issued');
|
|
76
76
|
assert.equal(res._redirect.code, 302);
|
|
77
|
-
assert.equal(res._redirect.loc, '/api/
|
|
77
|
+
assert.equal(res._redirect.loc, '/api/bongos/auth/web/start');
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
await t('authenticated request → next() called, no redirect', async () => {
|
|
@@ -95,7 +95,7 @@ await t('session lookup error → fails CLOSED (redirect, next() NOT called)', a
|
|
|
95
95
|
let nexted = false;
|
|
96
96
|
await auth.requireBuilderPage(req, res, () => { nexted = true; });
|
|
97
97
|
assert.equal(nexted, false, 'must not serve the page when the lookup errors');
|
|
98
|
-
assert.ok(res._redirect && res._redirect.loc === '/api/
|
|
98
|
+
assert.ok(res._redirect && res._redirect.loc === '/api/bongos/auth/web/start',
|
|
99
99
|
'must redirect to sign-in on a lookup error (fail closed)');
|
|
100
100
|
});
|
|
101
101
|
|
|
@@ -118,7 +118,7 @@ await t('box-scoped session → 302 to sign-in even though its builder holds the
|
|
|
118
118
|
let nexted = false;
|
|
119
119
|
await auth.requireBuilderPage(req, res, () => { nexted = true; });
|
|
120
120
|
assert.equal(nexted, false, 'a box session must not be served a gated page shell');
|
|
121
|
-
assert.ok(res._redirect && res._redirect.loc === '/api/
|
|
121
|
+
assert.ok(res._redirect && res._redirect.loc === '/api/bongos/auth/web/start',
|
|
122
122
|
'the remedy is a different session (/builder-reauth), so sign-in — not deniedTo');
|
|
123
123
|
});
|
|
124
124
|
|
|
@@ -129,7 +129,7 @@ await t('a source the registry does not declare → denied, never treated as uns
|
|
|
129
129
|
let nexted = false;
|
|
130
130
|
await auth.requireBuilderPage(req, res, () => { nexted = true; });
|
|
131
131
|
assert.equal(nexted, false, 'an unrecognised scope must fail closed, exactly as requireBuilder does');
|
|
132
|
-
assert.ok(res._redirect && res._redirect.loc === '/api/
|
|
132
|
+
assert.ok(res._redirect && res._redirect.loc === '/api/bongos/auth/web/start');
|
|
133
133
|
});
|
|
134
134
|
|
|
135
135
|
await t('cli and web sessions are untouched by the scope check', async () => {
|
|
@@ -21,22 +21,22 @@ const req = (cookie) => ({ headers: cookie ? { cookie } : {} });
|
|
|
21
21
|
|
|
22
22
|
test('the retry door carries the wizard return and the repo-scope opt-in while their cookies are valid', () => {
|
|
23
23
|
assert.equal(recoveryStartHref(req('gds_return=%2Fprojects%3Fview%3Dnew; gds_oauth_repos=1')),
|
|
24
|
-
'/api/
|
|
24
|
+
'/api/bongos/auth/web/start?return=%2Fprojects%3Fview%3Dnew&repos=1');
|
|
25
25
|
assert.equal(recoveryStartHref(req('gds_return=%2Fprojects%3Fview%3Dnew')),
|
|
26
|
-
'/api/
|
|
27
|
-
assert.equal(recoveryStartHref(req('gds_oauth_repos=1')), '/api/
|
|
26
|
+
'/api/bongos/auth/web/start?return=%2Fprojects%3Fview%3Dnew', 'a hall sign-in never asks for repos');
|
|
27
|
+
assert.equal(recoveryStartHref(req('gds_oauth_repos=1')), '/api/bongos/auth/web/start?repos=1');
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
test('with nothing left to rebuild from, the door is the bare start — never a guess', () => {
|
|
31
|
-
assert.equal(recoveryStartHref(req('')), '/api/
|
|
32
|
-
assert.equal(recoveryStartHref(req('gds_session=abc')), '/api/
|
|
33
|
-
assert.equal(recoveryStartHref(req('gds_oauth_repos=0')), '/api/
|
|
31
|
+
assert.equal(recoveryStartHref(req('')), '/api/bongos/auth/web/start');
|
|
32
|
+
assert.equal(recoveryStartHref(req('gds_session=abc')), '/api/bongos/auth/web/start');
|
|
33
|
+
assert.equal(recoveryStartHref(req('gds_oauth_repos=0')), '/api/bongos/auth/web/start', 'only the literal opt-in counts');
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
test('the door is under the same open-redirect allowlist as the callback', () => {
|
|
37
|
-
assert.equal(recoveryStartHref(req('gds_return=https%3A%2F%2Fevil.example%2Fx')), '/api/
|
|
38
|
-
assert.equal(recoveryStartHref(req('gds_return=%2F%2Fevil.example')), '/api/
|
|
39
|
-
assert.equal(recoveryStartHref(req('gds_return=javascript%3Aalert(1)')), '/api/
|
|
37
|
+
assert.equal(recoveryStartHref(req('gds_return=https%3A%2F%2Fevil.example%2Fx')), '/api/bongos/auth/web/start');
|
|
38
|
+
assert.equal(recoveryStartHref(req('gds_return=%2F%2Fevil.example')), '/api/bongos/auth/web/start');
|
|
39
|
+
assert.equal(recoveryStartHref(req('gds_return=javascript%3Aalert(1)')), '/api/bongos/auth/web/start');
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
test('every OAuth error page and the pending page rebuild their door from the cookies', () => {
|
|
@@ -47,8 +47,8 @@ test('every OAuth error page and the pending page rebuild their door from the co
|
|
|
47
47
|
'GitHub refused · State mismatch · handshake threw — three pages, three doors');
|
|
48
48
|
assert.match(callback, /renderAccessPendingPage\(err\.login, recoveryStartHref\(req\)\)/, 'the auto-walk-in lands where the founder was going');
|
|
49
49
|
assert.match(callback, /const onWayToProject = founderReturn\.startsWith\('\/projects'\);/, 'the founder-shaped NOT_APPROVED note');
|
|
50
|
-
assert.match(SRC, /const cta = opts\.cta \|\| \{ href: opts\.startHref \|\| '\/api\/
|
|
51
|
-
assert.match(SRC, /data-start="\$\{escapeHtml\(startHref \|\| '\/api\/
|
|
50
|
+
assert.match(SRC, /const cta = opts\.cta \|\| \{ href: opts\.startHref \|\| '\/api\/bongos\/auth\/web\/start', label: copy\.ctaLabel \};/);
|
|
51
|
+
assert.match(SRC, /data-start="\$\{escapeHtml\(startHref \|\| '\/api\/bongos\/auth\/web\/start'\)\}"/, 'the pending page reads its start from a data attribute, never string-built into script');
|
|
52
52
|
assert.match(SRC, /function land\(\) \{ window\.location\.href = start; \}/);
|
|
53
53
|
});
|
|
54
54
|
|
package/tests/bongos_login.mjs
CHANGED
|
@@ -16,12 +16,15 @@ const require = createRequire(import.meta.url);
|
|
|
16
16
|
const { normalizeInstanceBase, pollDecision } = require('../scripts/gds/login.js');
|
|
17
17
|
const LOGIN_JS = path.join(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'), 'scripts', 'gds', 'login.js');
|
|
18
18
|
|
|
19
|
-
test('normalizeInstanceBase adds https, strips trailing slashes + a pasted /api/
|
|
19
|
+
test('normalizeInstanceBase adds https, strips trailing slashes + a pasted /api/bongos', () => {
|
|
20
20
|
assert.equal(normalizeInstanceBase('example.com'), 'https://example.com');
|
|
21
21
|
assert.equal(normalizeInstanceBase('https://example.com/'), 'https://example.com');
|
|
22
22
|
assert.equal(normalizeInstanceBase('https://example.com///'), 'https://example.com');
|
|
23
|
+
assert.equal(normalizeInstanceBase('https://example.com/api/bongos'), 'https://example.com');
|
|
24
|
+
assert.equal(normalizeInstanceBase('https://example.com/api/bongos/'), 'https://example.com');
|
|
25
|
+
assert.equal(normalizeInstanceBase('https://example.com/api/bongos/v1'), 'https://example.com');
|
|
26
|
+
// the permanent alias is still a legal paste — task 1003707 moved the callers, not the door
|
|
23
27
|
assert.equal(normalizeInstanceBase('https://example.com/api/gds'), 'https://example.com');
|
|
24
|
-
assert.equal(normalizeInstanceBase('https://example.com/api/gds/'), 'https://example.com');
|
|
25
28
|
assert.equal(normalizeInstanceBase('http://localhost:3000'), 'http://localhost:3000');
|
|
26
29
|
});
|
|
27
30
|
|
|
@@ -58,10 +61,10 @@ test('login on a Device-Flow-disabled instance explains the cause and the cure',
|
|
|
58
61
|
res.writeHead(code, { 'Content-Type': 'application/json' });
|
|
59
62
|
res.end(JSON.stringify(body));
|
|
60
63
|
};
|
|
61
|
-
if (req.url.endsWith('/api/
|
|
64
|
+
if (req.url.endsWith('/api/bongos/instance')) {
|
|
62
65
|
return send(200, { schema: 'instance-manifest/v1', name: 'Stub', admission: { policy: 'invite-only' } });
|
|
63
66
|
}
|
|
64
|
-
if (req.url.endsWith('/api/
|
|
67
|
+
if (req.url.endsWith('/api/bongos/auth/device/start')) {
|
|
65
68
|
// Byte-for-byte what a real instance returned when its App had the box unticked.
|
|
66
69
|
return send(424, { error: { code: 'device_start_failed', message: 'device/code failed (400): {"error":"device_flow_disabled","error_description":"Device Flow must be explicitly enabled for this App"}' } });
|
|
67
70
|
}
|
package/tests/box_env.mjs
CHANGED
|
@@ -20,15 +20,15 @@ const box = require('../scripts/gds/box.js');
|
|
|
20
20
|
|
|
21
21
|
const { test, summary } = makeRunner();
|
|
22
22
|
|
|
23
|
-
await test('bakes GDS_BASE as the FULL api base (origin + /api/
|
|
23
|
+
await test('bakes GDS_BASE as the FULL api base (origin + /api/bongos) — matches box-report-*.sh, not box-heartbeat.sh\'s bare-origin BASE', () => {
|
|
24
24
|
const env = box.buildBoxEnv({ apiOrigin: 'https://cloudbongos.com' });
|
|
25
|
-
assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/
|
|
25
|
+
assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/bongos$/m);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
await test('strips a trailing slash off the origin before appending /api/
|
|
28
|
+
await test('strips a trailing slash off the origin before appending /api/bongos', () => {
|
|
29
29
|
const env = box.buildBoxEnv({ apiOrigin: 'https://cloudbongos.com/' });
|
|
30
|
-
assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/
|
|
31
|
-
assert.ok(!env.includes('//api/
|
|
30
|
+
assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/bongos$/m);
|
|
31
|
+
assert.ok(!env.includes('//api/bongos'), 'must not double the slash');
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
await test('no named tunnel: box.env carries GDS_BASE and nothing else', () => {
|
|
@@ -44,7 +44,7 @@ await test('named tunnel: box.env carries GDS_BASE AND all four tunnel vars', ()
|
|
|
44
44
|
credential: 'cred456', previewHostname: 'sandbox-alice.example.com',
|
|
45
45
|
},
|
|
46
46
|
});
|
|
47
|
-
assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/
|
|
47
|
+
assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/bongos$/m);
|
|
48
48
|
assert.match(env, /^BOX_TUNNEL_TOKEN=tok123$/m);
|
|
49
49
|
assert.match(env, /^BOX_TERMINAL_HOSTNAME=term-alice\.example\.com$/m);
|
|
50
50
|
assert.match(env, /^BOX_TERMINAL_CREDENTIAL=cred456$/m);
|
|
@@ -101,7 +101,7 @@ await t('persistImageFromUrl: content-type says png but bytes are not → sniff_
|
|
|
101
101
|
await t('persistImageFromUrl: valid PNG → written to disk, returns durable url', async () => {
|
|
102
102
|
const r = await at.persistImageFromUrl('https://cdn.discordapp.com/a.png', { messageId: 'm42', fetchImpl: fakeFetch(PNG), dir: TMP });
|
|
103
103
|
assert.equal(r.ok, true);
|
|
104
|
-
assert.match(r.url, /^\/api\/
|
|
104
|
+
assert.match(r.url, /^\/api\/bongos\/bug-attachments\/bug-m42-[0-9a-f]{16}\.png$/);
|
|
105
105
|
assert.equal(at.isSafeName(r.file), true);
|
|
106
106
|
const onDisk = await fs.readFile(path.join(TMP, r.file));
|
|
107
107
|
assert.equal(onDisk.length, PNG.length);
|
package/tests/cli_sessions.mjs
CHANGED
|
@@ -259,7 +259,7 @@ test('login VERIFIES a stored token before trusting it, and can be forced past',
|
|
|
259
259
|
// A stored token may be expired or revoked. Reinstating one unchecked would leave the builder
|
|
260
260
|
// "signed in" to a session every later command then fails on.
|
|
261
261
|
assert.match(src, /loadStoredSession\(base\)/);
|
|
262
|
-
assert.match(src, /\/api\/
|
|
262
|
+
assert.match(src, /\/api\/bongos\/me`, \{ headers: \{ Authorization/);
|
|
263
263
|
assert.match(src, /if \(me\.ok && me\.data && me\.data\.builder\)/);
|
|
264
264
|
assert.match(src, /--force/, 'there must be a way to sign in as somebody else');
|
|
265
265
|
});
|
package/tests/dev_lib.mjs
CHANGED
|
@@ -211,7 +211,7 @@ t('stop: kills a live pid, reports not-running otherwise', () => {
|
|
|
211
211
|
await ta('health: up + authConfigured parsed from the two healthz routes', async () => {
|
|
212
212
|
const params = { port: 3006 };
|
|
213
213
|
const deps = { fetchImpl: async (url) => {
|
|
214
|
-
if (url.endsWith('/api/
|
|
214
|
+
if (url.endsWith('/api/bongos/healthz')) return { status: 200, json: async () => ({ ok: true, auth_configured: true }) };
|
|
215
215
|
if (url.endsWith('/healthz')) return { status: 200 };
|
|
216
216
|
return { status: 404 };
|
|
217
217
|
} };
|
package/tests/discord_bugs.mjs
CHANGED
|
@@ -99,7 +99,7 @@ function makeDeps(over = {}) {
|
|
|
99
99
|
calls.persist.push({ urls, opts });
|
|
100
100
|
if (over.persistThrows) throw new Error('persist boom');
|
|
101
101
|
// default: echo each url back as a stored ref unless overridden
|
|
102
|
-
return over.stored ?? urls.map((u, i) => ({ file: `bug-x-${i}.png`, url: `/api/
|
|
102
|
+
return over.stored ?? urls.map((u, i) => ({ file: `bug-x-${i}.png`, url: `/api/bongos/bug-attachments/bug-x-${i}.png` }));
|
|
103
103
|
},
|
|
104
104
|
};
|
|
105
105
|
return { deps, calls };
|
|
@@ -282,7 +282,7 @@ await t('recordInboundBug: text + images → persists images + embeds durable li
|
|
|
282
282
|
assert.equal(calls.persist.length, 1);
|
|
283
283
|
assert.deepEqual(calls.persist[0].urls, ['https://cdn.discordapp.com/a.png']);
|
|
284
284
|
assert.match(calls.create[0].bodyMd, /Attachments \(1\)/);
|
|
285
|
-
assert.match(calls.create[0].bodyMd, /!\[attachment 1\]\(\/api\/
|
|
285
|
+
assert.match(calls.create[0].bodyMd, /!\[attachment 1\]\(\/api\/bongos\/bug-attachments\//);
|
|
286
286
|
});
|
|
287
287
|
|
|
288
288
|
await t('recordInboundBug: image-only (empty text) → filed with screenshot title', async () => {
|
|
@@ -71,7 +71,7 @@ function makeDeps(over = {}) {
|
|
|
71
71
|
persistImages: async (urls, opts) => {
|
|
72
72
|
calls.persist.push({ urls, opts });
|
|
73
73
|
if (over.persistThrows) throw new Error('persist boom');
|
|
74
|
-
return over.stored ?? urls.map((u, i) => ({ file: `bug-x-${i}.png`, url: `/api/
|
|
74
|
+
return over.stored ?? urls.map((u, i) => ({ file: `bug-x-${i}.png`, url: `/api/bongos/bug-attachments/bug-x-${i}.png` }));
|
|
75
75
|
},
|
|
76
76
|
};
|
|
77
77
|
return { deps, calls };
|
|
@@ -224,7 +224,7 @@ await t('recordInboundIdea: text + images → persists + embeds durable links',
|
|
|
224
224
|
assert.equal(r.images, 1);
|
|
225
225
|
assert.equal(calls.persist.length, 1);
|
|
226
226
|
assert.match(calls.capture[0].bodyMd, /Attachments \(1\)/);
|
|
227
|
-
assert.match(calls.capture[0].bodyMd, /!\[attachment 1\]\(\/api\/
|
|
227
|
+
assert.match(calls.capture[0].bodyMd, /!\[attachment 1\]\(\/api\/bongos\/bug-attachments\//);
|
|
228
228
|
});
|
|
229
229
|
|
|
230
230
|
await t('recordInboundIdea: UNLINKED author with image → still re-hosted (guards, not identity)', async () => {
|
|
@@ -280,6 +280,6 @@ test('the page reads the public feed and asks for JSON', async () => {
|
|
|
280
280
|
const r = render([]);
|
|
281
281
|
await settle();
|
|
282
282
|
assert.equal(r.requests.length, 1);
|
|
283
|
-
assert.equal(r.requests[0].url, '/api/
|
|
283
|
+
assert.equal(r.requests[0].url, '/api/bongos/projects/featured');
|
|
284
284
|
assert.equal(r.requests[0].opts.headers.Accept, 'application/json');
|
|
285
285
|
});
|
|
@@ -98,7 +98,7 @@ const GATE_FLOOR = {
|
|
|
98
98
|
// ADR 0157: `page.view.government` floor archon→metic.
|
|
99
99
|
requireGovernmentPage: 'metic',
|
|
100
100
|
};
|
|
101
|
-
const SIGN_IN = '/api/
|
|
101
|
+
const SIGN_IN = '/api/bongos/auth/web/start';
|
|
102
102
|
|
|
103
103
|
// --- doubles ----------------------------------------------------------------
|
|
104
104
|
function fakeRes() {
|
|
@@ -241,7 +241,7 @@ const costSummaryFixture = JSON.parse(
|
|
|
241
241
|
test('the treasury reads the endpoint that already carried the series — no new route', () => {
|
|
242
242
|
// The whole point of the task: the payload had both series all along, and the
|
|
243
243
|
// route's own comment calls daily[] "the treasury chart's cumulative line".
|
|
244
|
-
assert.match(drachmaeJs, /TREASURY_URL = '\/api\/
|
|
244
|
+
assert.match(drachmaeJs, /TREASURY_URL = '\/api\/bongos\/public\/cost-summary'/);
|
|
245
245
|
assert.ok(costSummaryFixture.daily.length, 'the payload really carries daily[]');
|
|
246
246
|
assert.ok(costSummaryFixture.daily_credits.length, 'and daily_credits[]');
|
|
247
247
|
assert.ok(Number(costSummaryFixture.total_usd) > 0, 'and the totals the prose states');
|
|
@@ -93,7 +93,7 @@ test('it describes NO second write path', () => {
|
|
|
93
93
|
// ends up sending a different payload than the form does, and the two records
|
|
94
94
|
// drift while both claim to be Full Ideas.
|
|
95
95
|
assert.ok(!/curl/i.test(SKILL), 'no hand-rolled HTTP');
|
|
96
|
-
assert.ok(!/api\.js POST \/api\/
|
|
96
|
+
assert.ok(!/api\.js POST \/api\/bongos\/inbox/.test(SKILL), 'no raw POST for filing an idea');
|
|
97
97
|
const grade = [...SKILL.matchAll(/grade\s*=\s*'([a-z]+)'/g)].map((m) => m[1]);
|
|
98
98
|
assert.ok(grade.every((g) => g === 'full'), `only the full grade is named: ${JSON.stringify(grade)}`);
|
|
99
99
|
});
|
package/tests/idp_federation.mjs
CHANGED
|
@@ -29,7 +29,7 @@ t('builds the hub /sso/authorize URL with client_id, redirect_uri, state', () =>
|
|
|
29
29
|
const url = auth.idpAuthorizeUrl('https://cloudbongos.com', 'client-abc', 'st8', 'https://proj.example.com/api/gds/auth/web/callback');
|
|
30
30
|
const u = new URL(url);
|
|
31
31
|
assert.equal(u.origin, 'https://cloudbongos.com');
|
|
32
|
-
assert.equal(u.pathname, '/api/
|
|
32
|
+
assert.equal(u.pathname, '/api/bongos/sso/authorize');
|
|
33
33
|
assert.equal(u.searchParams.get('client_id'), 'client-abc');
|
|
34
34
|
assert.equal(u.searchParams.get('redirect_uri'), 'https://proj.example.com/api/gds/auth/web/callback');
|
|
35
35
|
assert.equal(u.searchParams.get('state'), 'st8');
|
|
@@ -37,7 +37,7 @@ t('builds the hub /sso/authorize URL with client_id, redirect_uri, state', () =>
|
|
|
37
37
|
|
|
38
38
|
t('trims a trailing slash on the hub origin', () => {
|
|
39
39
|
const url = auth.idpAuthorizeUrl('https://cloudbongos.com/', 'c', 's', 'https://p/cb');
|
|
40
|
-
assert.equal(new URL(url).pathname, '/api/
|
|
40
|
+
assert.equal(new URL(url).pathname, '/api/bongos/sso/authorize');
|
|
41
41
|
assert.ok(!url.includes('com//api'), 'no double slash between origin and path');
|
|
42
42
|
});
|
|
43
43
|
|
package/tests/llm-cache.mjs
CHANGED
|
@@ -88,7 +88,7 @@ await arun('lookup: routes to apiCall on a HIT (right method/path/args)', async
|
|
|
88
88
|
const r = await c.lookup(KEY, { tokensSavedEst: 12 });
|
|
89
89
|
assert.equal(r.result_stdout, 'X');
|
|
90
90
|
assert.equal(calls[0][0], 'POST');
|
|
91
|
-
assert.equal(calls[0][1], '/api/
|
|
91
|
+
assert.equal(calls[0][1], '/api/bongos/llm-cache/lookup');
|
|
92
92
|
assert.deepEqual(calls[0][2], { cache_key: KEY, tokens_saved_est: 12 });
|
|
93
93
|
assert.deepEqual(calls[0][3], { allowUnauthenticated: true });
|
|
94
94
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// manifest per manage entry, EXECUTED (task 1003554).
|
|
3
3
|
//
|
|
4
4
|
// The defect this pins shut: entering /projects?view=manage fetched
|
|
5
|
-
// https://<project>/api/
|
|
5
|
+
// https://<project>/api/bongos/instance twice, identically and cross-origin,
|
|
6
6
|
// because the two cards that render a "what it runs right now" line — how the
|
|
7
7
|
// project is reached (brand.project.platformVisibility) and how people join
|
|
8
8
|
// (brand.project.joinability) — each asked the project for themselves. Two
|
|
@@ -99,7 +99,7 @@ test('the two cards of one manage entry cost ONE round trip, not two', async ()
|
|
|
99
99
|
|
|
100
100
|
// Assert
|
|
101
101
|
assert.equal(ui.requests.length, 1, 'one cross-origin GET served both lines');
|
|
102
|
-
assert.equal(ui.requests[0].url, 'https://demo.example.com/api/
|
|
102
|
+
assert.equal(ui.requests[0].url, 'https://demo.example.com/api/bongos/instance');
|
|
103
103
|
assert.equal(ui.requests[0].mode, 'cors', 'the project is somebody else’s origin');
|
|
104
104
|
for (const a of answers) {
|
|
105
105
|
assert.equal(a.ok, true);
|
|
@@ -151,7 +151,7 @@ test('switching projects is never served the previous project’s manifest', asy
|
|
|
151
151
|
|
|
152
152
|
// Assert
|
|
153
153
|
assert.equal(ui.requests.length, 2, 'the memo is keyed on the project, not merely present');
|
|
154
|
-
assert.equal(ui.requests[1].url, 'https://two.example.com/api/
|
|
154
|
+
assert.equal(ui.requests[1].url, 'https://two.example.com/api/bongos/instance');
|
|
155
155
|
});
|
|
156
156
|
|
|
157
157
|
test('a project that answered-and-refused RESOLVES carrying its status — both lines can say so', async () => {
|
|
@@ -150,7 +150,7 @@ await test('the page asks for exactly the ceiling, and asks for it ONCE', async
|
|
|
150
150
|
const h = harness({ count: 3 });
|
|
151
151
|
await tick(); await tick();
|
|
152
152
|
assert.equal(h.requests.length, 1, 'one directory read');
|
|
153
|
-
assert.match(h.requests[0], /\/api\/
|
|
153
|
+
assert.match(h.requests[0], /\/api\/bongos\/scouting\?limit=/);
|
|
154
154
|
const limit = Number(new URLSearchParams(h.requests[0].split('?')[1]).get('limit'));
|
|
155
155
|
assert.equal(limit, CEILING, `the page must ask for the route ceiling (${CEILING})`);
|
|
156
156
|
});
|
|
@@ -31,7 +31,7 @@ function test(name, fn) {
|
|
|
31
31
|
test('the seeding contract documents the self-check convention', () => {
|
|
32
32
|
assert.ok(NORM.includes('verifySeedCriteriaLinks'), 'names the helper function');
|
|
33
33
|
assert.ok(NORM.includes('seed-verify-criteria.js'), 'names the shared helper file');
|
|
34
|
-
assert.ok(NORM.includes('GET /api/
|
|
34
|
+
assert.ok(NORM.includes('GET /api/bongos/goals/<id>'), 'names the endpoint the self-check fetches');
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
test('the self-check is described as failing loudly on any mismatch, zero included', () => {
|
|
@@ -85,7 +85,7 @@ test('gated mode: a stranger meets the door on a page, with the way in on it', a
|
|
|
85
85
|
assert.equal(nexted, false);
|
|
86
86
|
assert.equal(res.statusCode, 401, 'a refused knock is a 401, not a 200 or a redirect');
|
|
87
87
|
assert.match(res.body, /Sign in/, 'the door carries the way in');
|
|
88
|
-
assert.match(res.body, /href="\/api\/
|
|
88
|
+
assert.match(res.body, /href="\/api\/bongos\/auth\/web\/start\?return=%2Fprojects%3Fview%3Dmap"/,
|
|
89
89
|
'the sign-in start returns the member to the page they knocked on — RELATIVE, which safeReturnTo honours everywhere');
|
|
90
90
|
assert.match(res.body, /Spike Harbor/, 'it names the project');
|
|
91
91
|
assert.match(res.body, /noindex/, 'a members-only project is not indexed');
|
|
@@ -172,7 +172,7 @@ test('the exempt list: the door, the manifest, the probes, the downloads — on
|
|
|
172
172
|
'/api/bongos/v1/public/progress', '/api/gds/instance/anything', '/instance', '/healthzz', '/downloads',
|
|
173
173
|
'/api/other/instance', '/api/bongos/provisioning/instances',
|
|
174
174
|
// the apply door is METHOD-scoped, so the bare path — no verb — is not exempt
|
|
175
|
-
'/api/
|
|
175
|
+
'/api/bongos/access-requests', '/api/bongos/access-requests/status',
|
|
176
176
|
]) assert.equal(isExempt(p), false, `${p} must be gated`);
|
|
177
177
|
});
|
|
178
178
|
|
|
@@ -184,7 +184,7 @@ test('the apply door: POST <api>/access-requests answers a stranger — and only
|
|
|
184
184
|
for (const p of [
|
|
185
185
|
'/api/gds/access-requests', '/api/bongos/access-requests', '/api/bongos/v1/access-requests',
|
|
186
186
|
// the router's own tolerances, the same ones the rest of the list is held to
|
|
187
|
-
'/API/BONGOS/ACCESS-REQUESTS', '/api/
|
|
187
|
+
'/API/BONGOS/ACCESS-REQUESTS', '/api/bongos/access-requests/',
|
|
188
188
|
]) assert.equal(isExempt(p, 'POST'), true, `POST ${p} must reach the apply route`);
|
|
189
189
|
|
|
190
190
|
// The bare GET on that path is the OWNER'S QUEUE (requireBuilder +
|
|
@@ -192,15 +192,15 @@ test('the apply door: POST <api>/access-requests answers a stranger — and only
|
|
|
192
192
|
// in front of it regardless — an exemption that ignored the verb would have
|
|
193
193
|
// silently removed a layer from the queue that lists would-be builders by name.
|
|
194
194
|
for (const m of ['GET', 'HEAD', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', '']) {
|
|
195
|
-
assert.equal(isExempt('/api/
|
|
195
|
+
assert.equal(isExempt('/api/bongos/access-requests', m), false, `${m || '(no verb)'} on the queue must stay gated`);
|
|
196
196
|
}
|
|
197
197
|
// and the exemption does not spread down the path
|
|
198
|
-
for (const p of ['/api/
|
|
198
|
+
for (const p of ['/api/bongos/access-requests/status', '/api/bongos/access-requests/invite', '/api/bongos/access-requests/1']) {
|
|
199
199
|
assert.equal(isExempt(p, 'POST'), false, `POST ${p} must stay gated`);
|
|
200
200
|
}
|
|
201
201
|
// a method-BLIND entry is unchanged by the new shape: it still exempts any verb
|
|
202
202
|
assert.equal(isExempt('/healthz', 'POST'), true, 'a bare-RegExp entry ignores the verb');
|
|
203
|
-
assert.equal(isExempt('/api/
|
|
203
|
+
assert.equal(isExempt('/api/bongos/instance', 'GET'), true);
|
|
204
204
|
});
|
|
205
205
|
|
|
206
206
|
// task 1003525 — the other half of the apply door. `bongos login` cannot re-poll the
|
|
@@ -210,15 +210,15 @@ test('the status poll: GET <api>/access-requests/status answers a stranger — t
|
|
|
210
210
|
for (const p of [
|
|
211
211
|
'/api/gds/access-requests/status', '/api/bongos/access-requests/status',
|
|
212
212
|
'/api/bongos/v1/access-requests/status',
|
|
213
|
-
'/API/BONGOS/ACCESS-REQUESTS/STATUS', '/api/
|
|
213
|
+
'/API/BONGOS/ACCESS-REQUESTS/STATUS', '/api/bongos/access-requests/status/',
|
|
214
214
|
]) assert.equal(isExempt(p, 'GET'), true, `GET ${p} must reach the status route`);
|
|
215
215
|
|
|
216
216
|
// the two halves do not lend each other their verbs
|
|
217
|
-
assert.equal(isExempt('/api/
|
|
218
|
-
assert.equal(isExempt('/api/
|
|
217
|
+
assert.equal(isExempt('/api/bongos/access-requests/status', 'POST'), false, 'the status route takes no write');
|
|
218
|
+
assert.equal(isExempt('/api/bongos/access-requests', 'GET'), false, 'the owner queue is still not a status poll');
|
|
219
219
|
|
|
220
220
|
// and neither opens the review surfaces that share the prefix
|
|
221
|
-
for (const p of ['/api/
|
|
221
|
+
for (const p of ['/api/bongos/access-requests/invite', '/api/bongos/access-requests/1/approve', '/api/bongos/access-requests/1']) {
|
|
222
222
|
for (const m of ['GET', 'POST']) {
|
|
223
223
|
assert.equal(isExempt(p, m), false, `${m} ${p} must stay gated`);
|
|
224
224
|
}
|
|
@@ -238,10 +238,10 @@ test('gated mode: an exempt path is never looked up, and a CORS preflight passes
|
|
|
238
238
|
});
|
|
239
239
|
|
|
240
240
|
test('the sign-in return is the knocked-on page for GET/HEAD only, relative, and never a foreign host', () => {
|
|
241
|
-
assert.equal(signInHref(fakeReq({ path: '/builders/roadmap' })), '/api/
|
|
242
|
-
assert.equal(signInHref(fakeReq({ path: '/builders/roadmap', method: 'POST' })), '/api/
|
|
243
|
-
assert.equal(signInHref(fakeReq({ path: '//evil.example/x' })), '/api/
|
|
244
|
-
assert.equal(signInHref(fakeReq({ path: '/' })), '/api/
|
|
241
|
+
assert.equal(signInHref(fakeReq({ path: '/builders/roadmap' })), '/api/bongos/auth/web/start?return=%2Fbuilders%2Froadmap');
|
|
242
|
+
assert.equal(signInHref(fakeReq({ path: '/builders/roadmap', method: 'POST' })), '/api/bongos/auth/web/start', 'a write has nothing safe to replay');
|
|
243
|
+
assert.equal(signInHref(fakeReq({ path: '//evil.example/x' })), '/api/bongos/auth/web/start', 'a protocol-relative path is dropped');
|
|
244
|
+
assert.equal(signInHref(fakeReq({ path: '/' })), '/api/bongos/auth/web/start', 'the front page needs no return');
|
|
245
245
|
});
|
|
246
246
|
|
|
247
247
|
// ── 2. the real booted app, pack = gated ─────────────────────────────────────
|
|
@@ -365,7 +365,7 @@ test('booted gated + apply: the status poll answers, and the review surfaces bes
|
|
|
365
365
|
assert.equal(j.error.code, 'bad_github_login', `GET ${p}: the status route answered, not the member door`);
|
|
366
366
|
}
|
|
367
367
|
// the owner's review surfaces share the prefix and stay behind the door
|
|
368
|
-
for (const p of ['/api/
|
|
368
|
+
for (const p of ['/api/bongos/access-requests', '/api/bongos/access-requests/invite']) {
|
|
369
369
|
const res = await request(p);
|
|
370
370
|
assert.equal(res.status, 401, `GET ${p} stays gated`);
|
|
371
371
|
assert.equal(JSON.parse(res.body).error.code, 'unauthenticated');
|