fix(ci): identify denied organization roots in access checks

Log the requested tenant, endpoint, operation and exposure for organization HTTP 401/403 responses. Keep credentials and upstream response bodies out of diagnostics and retain the deployment gate.

Validation: source checks and 118 tests pass, including forbidden-root identification and diagnostic privacy coverage.
This commit is contained in:
root committed 2026-11-11 11:35:36 +09:00
1 parent 7c09c89da5
commit bed970a175
3 files changed
+46 -1

No files matched your search

+30
View File
@@ -84,3 +84,33 @@ test('disabled verification makes no upstream requests', async () => {
fetchImpl: async () => assert.fail('disabled lookup'), log() {}
});
});
for (const status of [401, 403]) {
test(`HTTP ${status} diagnostics identify the requested tenant without exposing credentials or upstream data`, async () => {
const env = settings();
const logs = [];
await assert.rejects(verifyOrganization(env, {
fetchImpl: async () => response({ error: 'private-upstream-message', name: 'private-user', phone: '+8201000000000' }, status),
log: line => logs.push(line), pause: async () => assert.fail('must not retry access denial')
}), new RegExp('org_context_http_' + status));
const diagnostic = JSON.parse(logs[0]);
assert.equal(diagnostic.httpStatus, status);
assert.equal(diagnostic.endpoint, 'https://sadmin.hmac.kr/api/v1/integrations/org-context');
assert.equal(diagnostic.tenantId, ROOT);
assert.equal(diagnostic.operation, 'baron.org-context.read');
assert.equal(diagnostic.exposure, 'identifiers');
for (const hidden of [env.ORG_CONTEXT_KEY_ID, env.ORG_CONTEXT_KEY_SECRET, 'private-upstream-message', 'private-user', '+8201000000000']) {
assert.ok(!JSON.stringify(logs).includes(hidden));
}
});
}
test('a partial directory fails and diagnostics point to the forbidden root instead of a permitted root', async () => {
const deniedRoot = '9951229e-eea5-4376-96f4-78989bc3a506';
const logs = [];
await assert.rejects(verifyOrganization({ ...settings(), ORG_CONTEXT_TENANT_IDS: JSON.stringify([ROOT, deniedRoot]) }, {
fetchImpl: async url => new URL(url).searchParams.get('tenantId') === deniedRoot ? response({}, 403) : response(directory()),
log: line => logs.push(line), pause: async () => assert.fail('must not retry access denial')
}), /org_context_http_403/);
assert.deepEqual(logs.map(line => JSON.parse(line).tenantId), [deniedRoot]);
});