Merge candidate 20260909T101349Z-delivery-trust

Change-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot]
2026-09-09 11:44:29 +01:00
12 changed files with 418 additions and 0 deletions
+53
View File
@@ -72,6 +72,59 @@ jobs:
working-directory: tests/integration
run: node --test scripts/report-stable-e2e-failures.test.mjs
offline-org-provisioning:
name: Offline Organization provisioning
# Fixture acceptance only, not quarantine promotion or private RBAC proof.
runs-on: ubuntu-24.04
timeout-minutes: 25
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '24'
cache: 'npm'
cache-dependency-path: |
tests/integration/package-lock.json
frontend-modern/package-lock.json
internal/cloudcp/portal/frontend/package-lock.json
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
- name: Install locked dependencies
run: |
npm ci --prefix tests/integration
npm ci --prefix frontend-modern
npm ci --prefix internal/cloudcp/portal/frontend
cd tests/integration
npx playwright install --with-deps chromium
- name: Validate offline issuer boundaries
working-directory: tests/integration
run: >-
node --test scripts/offline-license-issuer.test.mjs
scripts/with-offline-entitlements.test.mjs
scripts/entitlement-bootstrap.test.mjs
- name: Prove authenticated default and created-org activation
working-directory: tests/integration
env:
PULSE_E2E_USE_LOCAL_BACKEND: 'true'
PULSE_E2E_SKIP_PLAYWRIGHT_INSTALL: 'true'
run: >-
node scripts/with-offline-entitlements.mjs node scripts/run-playwright.mjs
--config=playwright.multi-tenant-diagnostic.config.ts
--grep 'Scenario 1:|create, update, member manage' --workers=1 --retries=0
- name: Upload offline provisioning failure report
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: offline-org-provisioning-report
path: tests/integration/playwright-report/multi-tenant-diagnostic/
retention-days: 3
e2e:
name: Playwright Core E2E (shard ${{ matrix.shard }}/8)
needs: tier-selection
@@ -5318,3 +5318,29 @@ are distinct. Cached events and collection overhead limit timing inference.
synthetic Go pass/skip/fail output, producer exit retention, malformed input,
allowlisted targeting and unavailable resource evidence. This is not product
qualification; see `docs/RELEASE_RESOURCE_EVIDENCE.md`.
### Offline signed Organization provisioning
The isolated Community browser harness may provision signed entitlements only
against its run-local loopback issuer and freshly source-built non-release
backend. The managed backend must preserve the supplied public trust root and
issuer URL while keeping license signature bypass and mock mode disabled.
The issuer retains its private key in memory, binds status/refresh credentials
to each installation fingerprint, and remains available until backend cleanup.
A new issuer requires a fresh activation context; production fallback and
legacy-token exchange are not part of this fixture contract.
The shared Organization helper activates default and every created organisation
through the authenticated, explicitly scoped API, not by writing billing state
or copying activation persistence. It asserts advertised multi-tenancy, absent
Community private RBAC and non-demo security state. Without an offline fixture
key, existing activation behaviour is unchanged. The separate provisioning CI
job does not promote quarantined tests or establish private-runtime acceptance.
Verification: `tests/integration/scripts/managed-local-backend.test.mjs` checks
that the actual managed environment preserves the ephemeral issuer's trust and
strict-validation settings and uses the source-built Community target. Issuer
binding and lifecycle regressions are in `offline-license-issuer.test.mjs` and
`with-offline-entitlements.test.mjs`; the two scoped Chromium provisioning
scenarios verify the authenticated API/browser path. These are fixture proofs,
not release qualification or evidence that other Organization failures cleared.
@@ -0,0 +1,51 @@
# Offline Organization provisioning
This fixture is only for a source-built, non-release Community backend on the
same host as Playwright. It is not an installation workaround or a replacement
for private runtime implementations. No production account, licensing service,
admin endpoint or signing material is used.
After the normal locked installs in `tests/integration`, `frontend-modern` and
`internal/cloudcp/portal/frontend`, and Chromium installation, run from
`tests/integration`:
```sh
PULSE_E2E_USE_LOCAL_BACKEND=true node scripts/with-offline-entitlements.mjs \
node scripts/run-playwright.mjs \
--config=playwright.multi-tenant-diagnostic.config.ts \
--grep 'Scenario 1:|create, update, member manage' --workers=1 --retries=0
```
The wrapper generates an ephemeral Ed25519 issuer, binds it to loopback and
keeps it alive for the complete managed backend/browser lifecycle. The backend
is freshly built at a unique temporary path. Its development trust root and
licensing URL point to the issuer; signature bypass and mock mode are false.
The issuer has no outbound requests, redirect responses or production fallback.
It implements only activation and authenticated status/refresh, rejects legacy
exchange, and binds independent installation credentials to fingerprints.
Repeated activation for one fingerprint is idempotent. Issuer state lives for
this run, including backend restarts; restarting the issuer requires a fresh
run, not reusing an old activation directory. Never export fixture keys, grant
JWTs, installation credentials or backend runtime-state files as artifacts.
The Organization spec activates default through the authenticated API before
each scenario. `createOrg` independently activates each created organisation
with explicit scope headers. Capability assertions require `multi_tenant`,
exclude Community's private `rbac`, and check the security contract's
`sessionCapabilities.demoMode=false`. Offline activation suppresses the old
billing.json profile writer; there is no direct capability injection.
No offline key means the existing unentitled and other test paths are unchanged.
The separate CI provisioning job runs two narrow scenarios and issuer boundary
tests. It does not change stable/probation/quarantine membership. Passing it is
not Organization sharing acceptance, private-runtime RBAC coverage, full-suite
acceptance or release qualification. To investigate another Organization
scenario, use its explicit grep in the same diagnostic config and retain its
result separately. The Web owner judges those user-interface outcomes.
Local proof on 9 September 2026: two Chromium scenarios passed (3.8s test time)
on the final wrapper, with real authenticated activation and created-org scope;
13 focused Node cases passed for signatures, three distinct identities,
cross-identity/fingerprint/credential rejection, unsupported routes, ephemeral
keys, wrapper lifecycle and refusal of remote/release inputs. No hosted run or
release delivery is established by this proof.
@@ -136,6 +136,11 @@ export async function applyRequestedEntitlementProfile({
run = defaultRun,
fsModule = fs,
} = {}) {
// Signed offline activation is performed through the authenticated API, per org.
// Never inject billing capabilities alongside it.
if (trim(env.PULSE_E2E_OFFLINE_ACTIVATION_KEY)) {
return { applied: false, reason: 'signed_offline_activation' };
}
const request = resolveEntitlementProfile(env);
if (request.profile === '') {
return { applied: false, reason: 'no_profile_requested' };
@@ -117,3 +117,11 @@ test('applyRequestedEntitlementProfile fails for explicit live-instance runs wit
/no entitlement write target/i,
);
});
test('signed offline activation does not inject a billing profile', async () => {
const result = await applyRequestedEntitlementProfile({
env: { PULSE_E2E_OFFLINE_ACTIVATION_KEY: 'ephemeral', PULSE_MULTI_TENANT_ENABLED: 'true' },
run: () => { throw new Error('must not write billing state'); },
});
assert.deepEqual(result, { applied: false, reason: 'signed_offline_activation' });
});
@@ -453,3 +453,31 @@ test('owned runner orchestration proves reaping, signal cleanup and concurrent i
await run('python3', [path.join(scriptsDir, 'owned-run.test.py')], { timeout: 20000 });
await run(process.execPath, ['--test', path.join(scriptsDir, 'run-tests-interruption.test.mjs')], { timeout: 15000 });
});
test('managed offline provisioning preserves ephemeral trust and strict Community validation', async (t) => {
const { startOfflineLicenseIssuer } = await import('./offline-license-issuer.mjs');
const issuer = await startOfflineLicenseIssuer();
t.after(() => issuer.close());
const env = {
PULSE_E2E_RUN_ID: 'offline-provisioning-contract',
PULSE_LICENSE_PUBLIC_KEY: issuer.publicKey,
PULSE_LICENSE_SERVER_URL: issuer.url,
PULSE_LICENSE_DEV_MODE: 'false',
PULSE_MOCK_MODE: 'false',
PULSE_MULTI_TENANT_ENABLED: 'true',
PULSE_E2E_OFFLINE_ACTIVATION_KEY: issuer.activationKey,
};
const state = buildManagedLocalBackendState(env);
const backend = buildManagedLocalBackendEnv(state, env);
assert.equal(state.backendVariant, 'core');
assert.deepEqual(state.binaryBuildArgs, ['build', '-o', '__OUTPUT__', './cmd/pulse']);
for (const key of Object.keys(env).filter(key => key !== 'PULSE_E2E_RUN_ID')) {
assert.equal(backend[key], env[key], `${key} must reach the actual managed backend unchanged`);
}
assert.equal(new URL(backend.PULSE_LICENSE_SERVER_URL).hostname, '127.0.0.1');
assert.equal(Buffer.from(backend.PULSE_LICENSE_PUBLIC_KEY, 'base64').length, 32);
assert.equal(backend.PULSE_DATA_DIR, state.dataDir);
// Development orchestration remains independent of license validation bypass.
assert.equal(backend.PULSE_DEV, 'true');
assert.equal(backend.PULSE_LICENSE_DEV_MODE, 'false');
});
@@ -0,0 +1,81 @@
// Isolated non-release E2E issuer. No network clients or production credentials.
import { generateKeyPairSync, randomUUID, sign } from 'node:crypto';
import http from 'node:http';
const encode = value => Buffer.from(JSON.stringify(value)).toString('base64url');
export async function startOfflineLicenseIssuer() {
const { publicKey, privateKey } = generateKeyPairSync('ed25519');
const activationKey = `ppk_live_e2e_${randomUUID()}`;
const installations = new Map();
const fingerprints = new Map();
const grant = installation => {
const now = Math.floor(Date.now() / 1000);
const jti = `grt_${randomUUID()}`;
const claims = { iss: 'pulse-license', aud: 'pulse-relay', sub: installation.id,
lid: installation.license, iid: installation.id, lv: 1, st: 'active',
tier: 'msp', plan: 'msp_starter', iat: now, nbf: now, exp: now + 3600,
jti, email: 'e2e@example.invalid' };
const input = `${encode({ alg: 'EdDSA', typ: 'JWT' })}.${encode(claims)}`;
return { jwt: `${input}.${sign(null, Buffer.from(input), privateKey).toString('base64url')}`,
jti, expires_at: new Date(claims.exp * 1000).toISOString() };
};
const server = http.createServer(async (req, res) => {
const reply = (status, body) => {
res.writeHead(status, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
res.end(JSON.stringify(body));
};
if (req.method !== 'POST' || !['/v1/activate', '/v1/grants/status', '/v1/grants/refresh'].includes(req.url)) {
reply(404, { error: 'unsupported fixture route' }); return;
}
try {
let body = '';
for await (const chunk of req) {
body += chunk;
if (Buffer.byteLength(body) > 16384) { reply(413, { error: 'request too large' }); return; }
}
const data = JSON.parse(body);
if (!data || typeof data.instance_fingerprint !== 'string' || !data.instance_fingerprint.trim() || data.instance_fingerprint.length > 256) {
reply(400, { error: 'missing fixture fingerprint' }); return;
}
if (req.url === '/v1/activate') {
if (data.activation_key !== activationKey || data.runtime?.build !== 'community') {
reply(401, { error: 'invalid fixture activation' }); return;
}
let installation = fingerprints.get(data.instance_fingerprint);
if (!installation) {
if (installations.size >= 1024) { reply(429, { error: 'fixture capacity reached' }); return; }
installation = { id: `inst_${randomUUID()}`, license: `lic_${randomUUID()}`,
token: `pit_live_e2e_${randomUUID()}`, fingerprint: data.instance_fingerprint };
installations.set(installation.id, installation);
fingerprints.set(installation.fingerprint, installation);
}
reply(201, { license: { license_id: installation.license, state: 'active', tier: 'msp', license_version: 1 },
installation: { installation_id: installation.id, installation_token: installation.token, status: 'active' },
grant: grant(installation) });
return;
}
const installation = installations.get(data.installation_id);
if (!installation || req.headers.authorization !== `Bearer ${installation.token}` || data.instance_fingerprint !== installation.fingerprint) {
reply(401, { error: 'invalid fixture installation binding' }); return;
}
reply(200, req.url === '/v1/grants/status'
? { license_version: 1, refresh_required: false, server_time: new Date().toISOString(), status_policy: { recommended_check_after_sec: 300 } }
: { grant: grant(installation) });
} catch { if (!res.headersSent) reply(400, { error: 'invalid fixture request' }); }
});
server.requestTimeout = 5000;
server.headersTimeout = 5000;
await new Promise((resolve, reject) => {
server.once('error', reject);
server.listen(0, '127.0.0.1', resolve);
});
return {
url: `http://127.0.0.1:${server.address().port}`,
publicKey: Buffer.from(publicKey.export({ format: 'jwk' }).x, 'base64url').toString('base64'),
activationKey,
close: () => new Promise((resolve, reject) => {
server.close(error => error ? reject(error) : resolve());
server.closeAllConnections();
}),
};
}
@@ -0,0 +1,56 @@
import assert from 'node:assert/strict';
import { createPublicKey, verify } from 'node:crypto';
import test from 'node:test';
import { startOfflineLicenseIssuer } from './offline-license-issuer.mjs';
const post = (issuer, route, data, token = '') => fetch(issuer.url + route, {
method: 'POST', headers: { Authorization: `Bearer ${token}` }, body: JSON.stringify(data),
});
test('offline issuer signs scoped grants and binds status/refresh to each installation', async t => {
const issuer = await startOfflineLicenseIssuer();
t.after(() => issuer.close());
const activate = fingerprint => post(issuer, '/v1/activate', {
activation_key: issuer.activationKey, instance_fingerprint: fingerprint, runtime: { build: 'community' },
});
const responses = await Promise.all(['default', 'org-a', 'org-b'].map(activate));
assert.ok(responses.every(r => r.status === 201));
const states = await Promise.all(responses.map(r => r.json()));
assert.equal(new Set(states.map(s => s.installation.installation_id)).size, 3);
assert.equal(new Set(states.map(s => s.installation.installation_token)).size, 3);
const pub = createPublicKey({ format: 'jwk', key: { kty: 'OKP', crv: 'Ed25519',
x: Buffer.from(issuer.publicKey, 'base64').toString('base64url') } });
for (const [i, state] of states.entries()) {
const [head, body, signature] = state.grant.jwt.split('.');
assert.ok(verify(null, Buffer.from(`${head}.${body}`), pub, Buffer.from(signature, 'base64url')));
const claims = JSON.parse(Buffer.from(body, 'base64url'));
assert.equal(claims.iid, state.installation.installation_id);
assert.equal(claims.lid, state.license.license_id);
assert.equal(claims.st, 'active'); assert.equal(claims.tier, 'msp');
assert.equal(claims.feat, undefined); // Runtime derives features; no capability injection.
const data = { installation_id: claims.iid, instance_fingerprint: ['default', 'org-a', 'org-b'][i] };
for (const route of ['/v1/grants/status', '/v1/grants/refresh']) {
assert.equal((await post(issuer, route, data, state.installation.installation_token)).status, 200);
assert.equal((await post(issuer, route, data, 'wrong')).status, 401);
assert.equal((await post(issuer, route, { ...data, instance_fingerprint: 'wrong' }, state.installation.installation_token)).status, 401);
assert.equal((await post(issuer, route, data, states[(i + 1) % 3].installation.installation_token)).status, 401);
}
}
const repeated = await (await activate('org-a')).json();
assert.deepEqual(repeated.installation, states[1].installation);
});
test('offline issuer rejects unsupported routes, bad activation and malformed input', async t => {
const issuer = await startOfflineLicenseIssuer(); t.after(() => issuer.close());
const data = { activation_key: issuer.activationKey, instance_fingerprint: 'default', runtime: { build: 'community' } };
for (const mutation of [{ activation_key: 'wrong' }, { runtime: { build: 'enterprise' } }, { instance_fingerprint: '' }]) {
assert.ok((await post(issuer, '/v1/activate', { ...data, ...mutation })).status >= 400);
}
assert.equal((await post(issuer, '/v1/licenses/exchange', data)).status, 404);
assert.equal((await fetch(issuer.url + '/v1/activate')).status, 404);
assert.equal((await fetch(issuer.url + '/v1/activate', { method: 'POST', body: '{' })).status, 400);
assert.equal((await post(issuer, '/v1/activate', { ...data, extra: 'x'.repeat(17000) })).status, 413);
const other = await startOfflineLicenseIssuer(); t.after(() => other.close());
assert.notEqual(other.publicKey, issuer.publicKey);
assert.notEqual(other.activationKey, issuer.activationKey);
});
@@ -0,0 +1,46 @@
// Run the complete managed-local E2E lifecycle with an in-memory issuer.
import { mkdtemp, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { spawn } from 'node:child_process';
import { stopManagedLocalBackend } from './managed-local-backend.mjs';
import { startOfflineLicenseIssuer } from './offline-license-issuer.mjs';
const [command, ...args] = process.argv.slice(2);
if (!command) throw new Error('Usage: node scripts/with-offline-entitlements.mjs <command> [args...]');
if (process.env.PULSE_E2E_USE_LOCAL_BACKEND !== 'true') {
throw new Error('Offline issuer requires PULSE_E2E_USE_LOCAL_BACKEND=true; not Docker, remote or release binaries');
}
if (process.env.PULSE_E2E_LOCAL_BACKEND_BINARY || process.env.PULSE_E2E_LOCAL_BACKEND_VARIANT) {
throw new Error('Use the source-built Community managed backend, not a supplied binary/runtime');
}
for (const key of ['PULSE_BASE_URL', 'PULSE_E2E_USE_HOT_DEV', 'PULSE_E2E_SKIP_DOCKER', 'PULSE_E2E_RUNTIME_STATE_PATH', 'GOFLAGS']) {
if (process.env[key]) throw new Error(`Offline managed lifecycle does not accept ${key}`);
}
const binaryRoot = await mkdtemp(path.join(tmpdir(), 'pulse-offline-e2e-'));
const issuer = await startOfflineLicenseIssuer();
const runtimeEnv = { ...process.env, PULSE_E2E_RUNTIME_STATE_PATH: path.join(binaryRoot, 'runtime.json') };
try {
const child = spawn(command, args, { stdio: 'inherit', env: { ...runtimeEnv,
PULSE_E2E_LOCAL_BACKEND_BINARY: path.join(binaryRoot, 'pulse'),
PULSE_E2E_LOCAL_BACKEND_HOST: '127.0.0.1',
PULSE_LICENSE_PUBLIC_KEY: issuer.publicKey, PULSE_LICENSE_SERVER_URL: issuer.url,
PULSE_LICENSE_DEV_MODE: 'false', PULSE_MOCK_MODE: 'false', PULSE_MULTI_TENANT_ENABLED: 'true',
PULSE_E2E_OFFLINE_ACTIVATION_KEY: issuer.activationKey,
} });
const forward = signal => child.kill(signal);
const term = () => forward('SIGTERM');
const interrupt = () => forward('SIGINT');
process.on('SIGTERM', term); process.on('SIGINT', interrupt);
try {
process.exitCode = await new Promise((resolve, reject) => {
child.once('error', reject);
child.once('exit', (code, signal) => resolve(code ?? (signal === 'SIGINT' ? 130 : 143)));
});
} finally {
process.off('SIGTERM', term); process.off('SIGINT', interrupt);
}
} finally {
try { await stopManagedLocalBackend({ env: runtimeEnv }); }
finally { await issuer.close(); await rm(binaryRoot, { recursive: true, force: true }); }
}
@@ -0,0 +1,36 @@
import assert from 'node:assert/strict';
import { spawn } from 'node:child_process';
import test from 'node:test';
const script = new URL('./with-offline-entitlements.mjs', import.meta.url).pathname;
function run(args, extra = {}) {
return new Promise((resolve, reject) => {
const child = spawn(process.execPath, [script, ...args], {
env: { PATH: process.env.PATH, HOME: process.env.HOME, PULSE_E2E_USE_LOCAL_BACKEND: 'true', ...extra },
});
let output = '';
child.stdout.on('data', data => { output += data; });
child.stderr.on('data', data => { output += data; });
child.on('error', reject);
child.on('exit', code => resolve({ code, output }));
});
}
test('wrapper keeps issuer alive for child and closes it after child failure', async () => {
const result = await run([process.execPath, '-e', `
const assert = require('node:assert/strict');
assert.equal(process.env.PULSE_LICENSE_DEV_MODE, 'false');
assert.equal(process.env.PULSE_MOCK_MODE, 'false');
fetch(process.env.PULSE_LICENSE_SERVER_URL + '/v1/activate', {
method: 'POST', body: JSON.stringify({activation_key: process.env.PULSE_E2E_OFFLINE_ACTIVATION_KEY,
instance_fingerprint: 'test', runtime: {build: 'community'}})
}).then(r => { assert.equal(r.status, 201); console.log(process.env.PULSE_LICENSE_SERVER_URL); process.exitCode = 7; });
`]);
assert.equal(result.code, 7, result.output);
const url = result.output.trim().split('\n')[0];
await assert.rejects(fetch(url));
});
test('wrapper refuses remote, supplied binaries and release build flags before spawning', async () => {
for (const extra of [{ PULSE_BASE_URL: 'https://example.invalid' }, { PULSE_E2E_LOCAL_BACKEND_BINARY: '/tmp/release' }, { GOFLAGS: '-tags=release' }, { PULSE_E2E_USE_LOCAL_BACKEND: 'false' }]) {
const result = await run([process.execPath, '-e', "console.log('CHILD RAN')"], extra);
assert.notEqual(result.code, 0); assert.ok(!result.output.includes('\nCHILD RAN\n'));
}
});
@@ -3,6 +3,7 @@ import path from 'node:path';
import { test as base, expect } from '@playwright/test';
import {
apiRequest,
activateOfflineOrganization,
createAuthenticatedStorageState,
createOrg,
deleteOrg,
@@ -105,6 +106,12 @@ const expectStatusIn = (status: number, allowed: number[], context: string) => {
};
test.describe('Multi-tenant E2E flows', () => {
test.beforeEach(async ({ page }) => {
if (process.env.PULSE_E2E_OFFLINE_ACTIVATION_KEY) {
await ensureSessionAuthenticated(page);
await activateOfflineOrganization(page);
}
});
test('Scenario 1: feature flag visibility', async ({ page }) => {
await ensureAuthenticated(page);
+21
View File
@@ -1699,6 +1699,26 @@ const toOrgID = (displayName: string) => {
return `${base}-${suffix}`.slice(0, 64);
};
// Only the isolated issuer wrapper supplies this ephemeral key. Production and
// unentitled suites keep their normal activation state.
export async function activateOfflineOrganization(page: Page, orgId = "default"): Promise<void> {
const key = process.env.PULSE_E2E_OFFLINE_ACTIVATION_KEY;
if (!key) return;
const headers = { "X-Pulse-Org-ID": orgId, "X-Org-ID": orgId };
const activation = await apiRequest(page, "/api/license/activate", {
method: "POST", headers, data: { license_key: key },
});
if (!activation.ok()) throw new Error(`Offline org activation failed: ${activation.status()}`);
const response = await apiRequest(page, "/api/license/runtime-capabilities", { headers });
if (!response.ok()) throw new Error(`Offline capability lookup failed: ${response.status()}`);
const payload = await response.json();
const security = await apiRequest(page, "/api/security/status", { headers });
expect(security.ok()).toBe(true);
expect((await security.json()).sessionCapabilities.demoMode).toBe(false);
expect(payload.capabilities).toContain("multi_tenant");
expect(payload.capabilities).not.toContain("rbac");
}
export async function createOrg(
page: Page,
displayName: string,
@@ -1718,6 +1738,7 @@ export async function createOrg(
throw new Error("Failed to create org: response missing org id");
}
await activateOfflineOrganization(page, payload.id);
return { id: payload.id };
}