ci / verify (push) Canceled after 0s
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
41 lines
2.5 KiB
JavaScript
41 lines
2.5 KiB
JavaScript
// Read-only production checks on the independent handoff device. Never bind it,
|
|
// start a real conversation or print private keys/voice/MQTT credentials.
|
|
const fs = require('node:fs');
|
|
const crypto = require('node:crypto');
|
|
const net = require('node:net');
|
|
const assert = require('node:assert/strict');
|
|
const { sign } = require('../docs/embedded-signing-reference.cjs');
|
|
async function main() {
|
|
const init = JSON.parse(fs.readFileSync(process.argv[2], 'utf8').replace(/^\uFEFF/, ''));
|
|
assert.equal(init.factory_id, 'KP01-020000260914');
|
|
assert.equal(init.origin, 'https://82.157.201.114');
|
|
const health = await fetch(init.origin + '/health/ready', { signal: AbortSignal.timeout(15000) });
|
|
assert.equal(health.status, 200);
|
|
const offset = Date.parse(health.headers.get('date')) - Date.now();
|
|
assert.ok(Number.isFinite(offset));
|
|
const post = async (path, input) => {
|
|
const raw = JSON.stringify(input);
|
|
const headers = sign(Buffer.from(init.device_key_hex, 'hex'), { path, deviceId: init.factory_id,
|
|
keyVersion: init.key_version, timestamp: Date.now() + offset, nonce: crypto.randomBytes(16).toString('base64url'), requestId: crypto.randomUUID(), raw }).headers;
|
|
const response = await fetch(init.origin + path, { method: 'POST', headers, body: raw, signal: AbortSignal.timeout(15000) });
|
|
return { status: response.status, body: await response.json() };
|
|
};
|
|
const state = await post('/api/v1/device/ble-state', {});
|
|
assert.equal(state.status, 200);
|
|
assert.equal(state.body.data.bound, false, 'Test device is bound: skip any chat probe');
|
|
const start = await post('/api/v1/device/chat/start', { device_id: init.factory_id, session_id: crypto.randomUUID() });
|
|
assert.equal(start.status, 409);
|
|
assert.equal(start.body.code, 'DEVICE_UNBOUND');
|
|
const mqtt = await new Promise(resolve => {
|
|
const socket = net.connect({ host: '82.157.201.114', port: 1883 });
|
|
socket.setTimeout(8000);
|
|
socket.once('connect', () => { resolve('TCP_OK'); socket.destroy(); });
|
|
socket.once('timeout', () => { resolve('TIMEOUT'); socket.destroy(); });
|
|
socket.once('error', error => { resolve(error.code || 'TCP_FAILED'); socket.destroy(); });
|
|
});
|
|
console.log(JSON.stringify({ health: health.status, device_id: init.factory_id, bound: false,
|
|
chat_without_boot_id: start.status, chat_error: start.body.code, mqtt_public_tcp: mqtt,
|
|
startup_endpoints_called: 0, bindings_changed: 0, real_calls_started: 0 }));
|
|
}
|
|
main().catch(() => { console.error('Live probe failed; no private values printed.'); process.exitCode = 1; });
|