Deploy EG-BIM QA Gateway / deploy (push) Failing after 54s
Report documented operation, scope and exposure error codes, permitted exposure enums and proxy challenge indicators during deployment checks. Exclude arbitrary upstream messages and credential material while retaining failure on denied access. Validation: source checks and 123 tests pass. Retried staging run 227194 still returns org_context_http_403; the new diagnostic requires the user-managed push before a further run.
80 lines
3.5 KiB
JavaScript
80 lines
3.5 KiB
JavaScript
import { getOrgDirectory } from '../src/org-context.js';
|
|
import { deploymentOrgSettings } from './org-context-settings.mjs';
|
|
import { setTimeout as wait } from 'node:timers/promises';
|
|
import { pathToFileURL } from 'node:url';
|
|
|
|
// Only documented machine codes and enum values may be copied from an upstream error.
|
|
const accessErrorCodes = new Set([
|
|
'credential_operation_not_available', 'credential_operation_mismatch',
|
|
'credential_scope_exceeded', 'credential_exposure_exceeded',
|
|
'integration_credential_not_allowed', 'integration_credential_required',
|
|
'invalid_integration_credential', 'integration_credential_expired', 'credential_conflict'
|
|
]);
|
|
const exposures = new Set(['none', 'structure', 'members', 'identifiers']);
|
|
|
|
async function accessResponseDiagnostic(response) {
|
|
const type = response.headers.get('content-type') || '';
|
|
const responseKind = /json/i.test(type) ? 'json' : /html/i.test(type) ? 'html' : 'other';
|
|
let body;
|
|
if (responseKind === 'json') {
|
|
try { body = await response.clone().json(); } catch {}
|
|
}
|
|
const code = body?.code || body?.error;
|
|
return {
|
|
responseKind,
|
|
upstreamCode: accessErrorCodes.has(code) ? code : 'unrecognized',
|
|
grantedExposure: exposures.has(body?.details?.grantedExposure) ? body.details.grantedExposure : undefined,
|
|
requiredExposure: exposures.has(body?.details?.requiredExposure) ? body.details.requiredExposure : undefined,
|
|
proxyChallenge: response.headers.get('cf-mitigated') === 'challenge'
|
|
};
|
|
}
|
|
|
|
export async function verifyOrganization(env = process.env, { fetchImpl = fetch, pause = wait, log = console.log } = {}) {
|
|
const { vars, secrets } = deploymentOrgSettings(env);
|
|
if (vars.ORG_CONTEXT_ENABLED !== 'true') {
|
|
log('Organization integration disabled; existing behavior retained.');
|
|
return;
|
|
}
|
|
const checkedFetch = async (url, options) => {
|
|
const response = await fetchImpl(url, options);
|
|
if (response.status === 401 || response.status === 403) {
|
|
const request = new URL(url);
|
|
log(JSON.stringify({
|
|
status: 'organization_access_denied', httpStatus: response.status,
|
|
endpoint: request.origin + request.pathname,
|
|
tenantId: request.searchParams.get('tenantId'),
|
|
operation: 'baron.org-context.read', exposure: 'identifiers',
|
|
...await accessResponseDiagnostic(response)
|
|
}));
|
|
}
|
|
return response;
|
|
};
|
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
try {
|
|
// CI can wait for a slow upstream without extending the page request timeout.
|
|
const directory = await getOrgDirectory({ ...vars, ...secrets }, { fetchImpl: checkedFetch, timeoutMs: 15000 });
|
|
const summary = {
|
|
status: 'verified', rootCount: JSON.parse(vars.ORG_CONTEXT_TENANT_IDS).length,
|
|
tenantCount: directory.tenantCount, userCount: directory.byUser.size,
|
|
membershipCount: directory.membershipCount
|
|
};
|
|
log(JSON.stringify(summary));
|
|
return summary;
|
|
} catch (error) {
|
|
const retryable = /^org_context_(timeout|request_failed|http_(429|502|503|504))$/.test(error?.message || '');
|
|
if (!retryable || attempt === 3) throw error;
|
|
log(`Organization verification attempt ${attempt}/3 failed (${error.message}); retrying.`);
|
|
await pause(2000);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
try {
|
|
await verifyOrganization();
|
|
} catch (error) {
|
|
console.error(/^org_context_[a-z0-9_]+$/.test(error?.message || '') ? error.message : 'Organization integration configuration or verification failed.');
|
|
process.exitCode = 1;
|
|
}
|
|
}
|