1 parent
0d9b1fd703
commit
7c09c89da5
9 files changed
+202
-31
No files matched your search
@@ -0,0 +1,49 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { verifyAbc } from '../scripts/verify-abc.mjs';
|
||||
|
||||
const env = {
|
||||
CLOUDFLARE_API_TOKEN: 'fixture-cloudflare-token', SESSION_SECRET: 'fixture-session-'.repeat(3),
|
||||
ABC_API_KEY: 'fixture-project-key', AUTH_CLIENT_ID: 'fixture-public-pkce-client',
|
||||
ABC_PROJECT_ID: '01a1c543-ab4f-744f-8eff-ab85f2644271', ABC_CHANNEL_ID: '01a1c544-35ac-7674-9bf0-2469bfbe3e52',
|
||||
ORG_CONTEXT_ENABLED: 'true', ORG_CONTEXT_TENANT_IDS: '["038326b6-954a-48a7-a85f-efd83f62b82a"]',
|
||||
ORG_CONTEXT_KEY_ID: 'fixture-key-id', ORG_CONTEXT_KEY_SECRET: 'fixture-key-secret',
|
||||
DEPLOY_COMMIT_SHA: 'a'.repeat(40)
|
||||
};
|
||||
const fields = [{ key: 'title' }, { key: 'contents' }, {
|
||||
key: 'Category', options: ['ERROR_QNA', 'IMPROVEMENT_QNA', 'GENERAL_QNA'].map((key) => ({ key }))
|
||||
}];
|
||||
|
||||
test('ABC connection verification reads the configured production channel without writing data', async () => {
|
||||
await verifyAbc(env, async (url, options) => {
|
||||
assert.equal(url, 'https://qa.brsw.kr/api/projects/' + env.ABC_PROJECT_ID + '/channels/' + env.ABC_CHANNEL_ID + '/fields');
|
||||
assert.equal(options.method, 'GET');
|
||||
assert.equal(options.body, undefined);
|
||||
assert.equal(options.redirect, 'error');
|
||||
assert.equal(options.headers['x-api-key'], env.ABC_API_KEY);
|
||||
return Response.json(fields);
|
||||
});
|
||||
});
|
||||
|
||||
test('ABC connection verification blocks wrong production targets before sending credentials', async () => {
|
||||
let requests = 0;
|
||||
for (const override of [
|
||||
{ ABC_API_BASE_URL: 'https://feedback.hmac.kr' },
|
||||
{ ABC_CHANNEL_ID: '01900000-0000-7000-8000-000000000002' }
|
||||
]) {
|
||||
await assert.rejects(verifyAbc({ ...env, ...override }, async () => { requests++; }), /must match the production EGBIM Q&A target/);
|
||||
}
|
||||
assert.equal(requests, 0);
|
||||
});
|
||||
|
||||
test('ABC connection verification rejects wrong keys and channel schemas without printing credentials', async () => {
|
||||
for (const status of [401, 403, 404]) {
|
||||
await assert.rejects(verifyAbc(env, async () => new Response('', { status })), new RegExp('HTTP ' + status));
|
||||
}
|
||||
await assert.rejects(verifyAbc(env, async () => Response.json([{ key: 'title' }])), /contents, Category/);
|
||||
await assert.rejects(verifyAbc(env, async () => Response.json(fields.map((field) => ({ ...field, options: [] })))), /category options/);
|
||||
await assert.rejects(verifyAbc(env, async () => { throw new Error(env.ABC_API_KEY); }), (error) => {
|
||||
assert.ok(!error.message.includes(env.ABC_API_KEY));
|
||||
return true;
|
||||
});
|
||||
});
|
||||
@@ -12,8 +12,8 @@ import worker from '../src/index.js';
|
||||
const SHA = 'a'.repeat(40);
|
||||
const fixture = () => ({
|
||||
CLOUDFLARE_API_TOKEN: 'fixture-cloudflare-token', SESSION_SECRET: 'fixture-session-secret-'.repeat(3),
|
||||
ABC_API_KEY: 'fixture-abc-key', AUTH_CLIENT_ID: 'production-client', ABC_API_BASE_URL: 'https://feedback.example.test/',
|
||||
ABC_PROJECT_ID: '01900000-0000-7000-8000-000000000001', ABC_CHANNEL_ID: '01900000-0000-7000-8000-000000000002',
|
||||
ABC_API_KEY: 'fixture-abc-key', AUTH_CLIENT_ID: 'production-client', ABC_API_BASE_URL: 'https://qa.brsw.kr/',
|
||||
ABC_PROJECT_ID: '01a1c543-ab4f-744f-8eff-ab85f2644271', ABC_CHANNEL_ID: '01a1c544-35ac-7674-9bf0-2469bfbe3e52',
|
||||
ORG_CONTEXT_ENABLED: 'true', ORG_CONTEXT_TENANT_IDS: '["038326b6-954a-48a7-a85f-efd83f62b82a"]',
|
||||
ORG_CONTEXT_KEY_ID: 'fixture-org-key', ORG_CONTEXT_KEY_SECRET: 'fixture-org-secret', DEPLOY_COMMIT_SHA: SHA
|
||||
});
|
||||
@@ -24,8 +24,9 @@ test('production preserves dashboard-managed domains without requesting zone rou
|
||||
assert.match(config, /^workers_dev\s*=\s*false\s*$/m);
|
||||
});
|
||||
|
||||
test('production requires its own credentials, target IDs, organization lookup and immutable release', () => {
|
||||
test('production requires its own credentials, organization lookup and immutable release', () => {
|
||||
for (const name of Object.keys(fixture())) {
|
||||
if (['ABC_API_BASE_URL', 'ABC_PROJECT_ID', 'ABC_CHANNEL_ID'].includes(name)) continue;
|
||||
const env = fixture();
|
||||
delete env[name];
|
||||
assert.throws(() => productionSettings(env), new RegExp(name === 'ORG_CONTEXT_TENANT_IDS' ? 'org_context_invalid_tenants' : name));
|
||||
@@ -38,12 +39,48 @@ test('production requires its own credentials, target IDs, organization lookup a
|
||||
const settings = productionSettings(fixture());
|
||||
assert.equal(settings.worker, 'baron-qa-gateway-prod');
|
||||
assert.equal(settings.bucket, 'baron-qa-write');
|
||||
assert.equal(settings.vars.ABC_API_BASE_URL, 'https://feedback.example.test');
|
||||
assert.equal(settings.vars.ABC_API_BASE_URL, 'https://qa.brsw.kr');
|
||||
assert.equal(settings.vars.QA_ASSET_PREFIX, 'releases/' + SHA);
|
||||
for (const name of Object.keys(settings.secrets)) assert.equal(settings.vars[name], undefined);
|
||||
assert.equal(settings.secrets.CLOUDFLARE_API_TOKEN, undefined);
|
||||
});
|
||||
|
||||
test('production defaults connect the writing Worker to the production API and SSO', () => {
|
||||
const env = fixture();
|
||||
delete env.ABC_API_BASE_URL;
|
||||
delete env.ABC_PROJECT_ID;
|
||||
delete env.ABC_CHANNEL_ID;
|
||||
const settings = productionSettings(env);
|
||||
assert.equal(settings.vars.ABC_API_BASE_URL, 'https://qa.brsw.kr');
|
||||
assert.equal(settings.vars.ABC_PROJECT_ID, '01a1c543-ab4f-744f-8eff-ab85f2644271');
|
||||
assert.equal(settings.vars.ABC_CHANNEL_ID, '01a1c544-35ac-7674-9bf0-2469bfbe3e52');
|
||||
assert.equal(settings.vars.AUTH_AUTHORIZE_URL, 'https://app.brsw.kr/oidc/oauth2/auth');
|
||||
assert.equal(settings.vars.AUTH_TOKEN_URL, 'https://app.brsw.kr/oidc/oauth2/token');
|
||||
assert.equal(settings.vars.AUTH_USERINFO_URL, 'https://app.brsw.kr/oidc/userinfo');
|
||||
assert.equal(settings.vars.ORG_CONTEXT_API_URL, 'https://app.brsw.kr/api/v1/integrations/org-context');
|
||||
const custom = productionSettings({ ...env, AUTH_ISSUER: 'https://identity.example.test/oidc/' });
|
||||
assert.equal(custom.vars.AUTH_AUTHORIZE_URL, 'https://identity.example.test/oidc/oauth2/auth');
|
||||
assert.throws(() => productionSettings({ ...env, AUTH_ISSUER: 'http://identity.example.test' }), /AUTH_ISSUER/);
|
||||
});
|
||||
|
||||
test('production rejects staging API origins and other project or channel IDs', () => {
|
||||
for (const override of [
|
||||
{ ABC_API_BASE_URL: 'https://feedback.hmac.kr' },
|
||||
{ ABC_API_BASE_URL: 'https://qa-test.baroncs.co.kr' },
|
||||
{ ABC_PROJECT_ID: '01900000-0000-7000-8000-000000000001' },
|
||||
{ ABC_CHANNEL_ID: '01900000-0000-7000-8000-000000000002' }
|
||||
]) {
|
||||
assert.throws(() => productionSettings({ ...fixture(), ...override }), /must match the production EGBIM Q&A target/);
|
||||
withFakeWrangler(({ env, capture }) => {
|
||||
const result = spawnSync(process.execPath, [fileURLToPath(new URL('../scripts/deploy-production.mjs', import.meta.url))], {
|
||||
env: { ...env, ...override }, encoding: 'utf8'
|
||||
});
|
||||
assert.equal(result.status, 1, result.stderr);
|
||||
assert.equal(existsSync(capture), false);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function withFakeWrangler(body) {
|
||||
const dir = mkdtempSync(join(tmpdir(), 'qa-deploy-test-'));
|
||||
const capture = join(dir, 'commands.jsonl');
|
||||
|
||||
Reference in new issue
Block a user