SHA256
test: exercise native Android flows against pinned upstream HTTPS and OIDC
Add an ephemeral HTTPS proxy and standards-shaped RS256/S256-PKCE test IdP around the unmodified upstream checkout. Require unlocked devices and nonempty, failure-free JUnit evidence. The extended API 35 suite passes all seven cases, including native Blob/file transfer, session recreation, outage recovery, isolated OIDC and back navigation; eight evidence-verifier regressions also pass. API 37 and real-provider/device validation remain release gates.
This commit is contained in:
1 parent
f7b9dcd91e
commit
9ca11e4fb5
7 files changed
+691
No files matched your search
@@ -0,0 +1,53 @@
|
||||
// Test-only reverse proxy around the unmodified pinned upstream application.
|
||||
import fs from 'node:fs';
|
||||
import http from 'node:http';
|
||||
import https from 'node:https';
|
||||
import path from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { once } from 'node:events';
|
||||
import { startIdentityProvider } from './oidc-fixture.mjs';
|
||||
|
||||
const [upstream, directory] = process.argv.slice(2);
|
||||
process.env.PORT = '0';
|
||||
process.env.BIND_ADDRESS = '127.0.0.1';
|
||||
process.env.DB_PATH = path.join(directory, 'fixture.db');
|
||||
process.env.SESSION_SECRET = randomBytes(48).toString('hex');
|
||||
process.env.SESSION_SECURE = 'true';
|
||||
process.env.DB_ENCRYPTION_KEY = '';
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.LOG_LEVEL = 'warn';
|
||||
const tls = { key: fs.readFileSync(path.join(directory, 'key.pem')), cert: fs.readFileSync(path.join(directory, 'cert.pem')) };
|
||||
const idp = await startIdentityProvider(tls);
|
||||
process.env.OIDC_ISSUER = idp.issuer;
|
||||
process.env.OIDC_CLIENT_ID = idp.clientId;
|
||||
process.env.OIDC_CLIENT_SECRET = idp.secret;
|
||||
const { server } = await import(pathToFileURL(path.join(upstream, 'server/index.js')));
|
||||
if (!server.listening) await once(server, 'listening');
|
||||
let networkAvailable = true;
|
||||
const proxy = https.createServer(tls, (request, response) => {
|
||||
// Fault injection lives only in this loopback fixture, never in upstream/app code.
|
||||
if (request.method === 'POST' && ['/__mobile_test/network/off', '/__mobile_test/network/on'].includes(request.url)) {
|
||||
networkAvailable = request.url.endsWith('/on');
|
||||
response.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
response.end('{}');
|
||||
return;
|
||||
}
|
||||
if (!networkAvailable) { request.socket.destroy(); return; }
|
||||
const backend = http.request({
|
||||
hostname: '127.0.0.1', port: server.address().port,
|
||||
method: request.method, path: request.url,
|
||||
headers: { ...request.headers, 'x-forwarded-proto': 'https', 'x-forwarded-for': '127.0.0.1' },
|
||||
}, incoming => {
|
||||
response.writeHead(incoming.statusCode, incoming.headers);
|
||||
incoming.pipe(response);
|
||||
});
|
||||
backend.on('error', () => { response.writeHead(502); response.end(); });
|
||||
request.pipe(backend);
|
||||
});
|
||||
proxy.listen(0, '127.0.0.1');
|
||||
await once(proxy, 'listening');
|
||||
process.env.OIDC_REDIRECT_URI = `https://127.0.0.1:${proxy.address().port}/api/v1/auth/oidc/callback`;
|
||||
idp.setRedirect(process.env.OIDC_REDIRECT_URI);
|
||||
fs.writeFileSync(path.join(directory, 'ready.json'), JSON.stringify({ port: proxy.address().port, idpPort: idp.port }));
|
||||
process.on('SIGTERM', () => { idp.close(); proxy.close(); server.close(); process.exit(0); });
|
||||
Reference in new issue
Block a user