diff --git a/docs/api/fixture-policy.md b/docs/api/fixture-policy.md new file mode 100644 index 0000000..466c180 --- /dev/null +++ b/docs/api/fixture-policy.md @@ -0,0 +1,23 @@ +# Read-only fixture policy (Phase 0.3) + +Fixtures are schema-preserving, redacted responses from exactly two locally configured, password-free SimAdmin instances at upstream baseline `58e2204`. Instance identities and origins are never logged or persisted. + +## Selection and transport + +The OperationRegistry is the sole operation source. Collector initialization fingerprints every complete operation contract. Runtime validation requires the exact Registry object (not a look-alike), an unchanged structural fingerprint, `GET`, `R0`, and a fully bound path beginning with one `/api/`; it rejects absolute/scheme-relative URLs, query/hash, backslashes, duplicate slashes, dot segments, percent encoding, and single/double-decode changes. Selection and `collectOne` both enforce this policy before transport. + +Configuration is checked before normalization (so query/fragment stripping cannot hide an unsafe input), then passed through production `normalizeConfig`; collector-specific constraints require exactly two `http(s)` RFC1918 private-LAN IPv4 origins, no credentials, path, query, fragment, or authentication. `collectOne` repeats origin validation and verifies the final URL retains the exact origin and Registry path. Requests omit credentials, body, Authorization, and Cookie; redirects are manual, timeout is six seconds, and concurrency is two. + +Explicit denials are machine-readable in `DENY_REASONS`: operator scan and `/api/connectivity` are active operations (connectivity performs a ping); content/history/log/query endpoints are omitted where no Registry-backed privacy-safe bounded contract exists. No authentication retry occurs. + +## Data handling and schema preservation + +Raw responses exist only in memory. Before writing, every OperationRegistry `sensitiveFields` entry whose direction is `response` is executed as its endpoint-specific JSONPath; missing optional paths are safe no-ops and unsupported path syntax fails closed. Wildcard arrays are supported. Sensitive objects retain keys, arrays retain length and element shape, and primitive leaves retain their JSON types: strings become `[REDACTED]`, numbers `0`, booleans `false`, and null remains null. Objects and arrays are never stringified into placeholders. + +A recursive fallback sanitizer then covers credentials, access/device/private keys, PIN/PUK, subscriber/device/network identifiers, usernames/accounts, serials/revisions, filesystem/object paths, templates/config, URLs/hosts, IPv4/IPv6, phone-like and separated modem identifiers, and unknown high-entropy secrets. JSON encoded inside strings is parsed, recursively sanitized, and serialized back as a string. Unparseable templates are conservatively replaced. GPS/cell identifiers and device fingerprints (revision, uptime, traffic, precise timestamps) are type-preservingly redacted. Ordinary API `message` status semantics and manual-entry booleans are retained unless an operation path declares them sensitive; SMS/call content remains denied or explicitly redacted. + +## Manifest and verification + +Real and synthetic fixtures are strictly separated; synthetic fixtures, if introduced, must be under `synthetic-errors/`, set `synthetic: true`, and never contribute to real coverage. The manifest file set must exactly equal disk contents, with unique paths and operation/alias pairs, exact domain counts, SHA-256 and sizes. The separately reviewed `response-shapes-58e2204.json` records value-free recursive payload signatures (object keys, every array element, and primitive types) for exactly all 78 alias/operation pairs. It is excluded from `manifest.files` to avoid a cycle but pinned by the manifest `shapeBaseline` size and SHA-256. Capture requires and attests it but never creates or overwrites it. Tests strictly validate its schema and compare every payload to it. Envelopes enforce allowed aliases, date-only reasonable `capturedAt`, Registry correspondence, and category-specific HTTP/content-type/payload consistency. + +Tests recursively collect every configured string leaf of length at least three (including tags, capabilities, auth, and password) and assert none occurs in fixtures without printing values. Credential scans report counts only. Capture logs are limited to alias, operation ID, and result category. diff --git a/packages/test-fixtures/scripts/collect-readonly-fixtures.ts b/packages/test-fixtures/scripts/collect-readonly-fixtures.ts new file mode 100644 index 0000000..440d1cc --- /dev/null +++ b/packages/test-fixtures/scripts/collect-readonly-fixtures.ts @@ -0,0 +1,40 @@ +import { readFile, mkdir, writeFile, rm, readdir, stat } from 'node:fs/promises'; +import { createHash } from 'node:crypto'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { upstream58e2204Operations } from '../../operation-registry/src/upstream-58e2204.ts'; +import { normalizeConfig } from '../../../server/config/schema.js'; +import { collectOne, selectReadonlyOperations, validateInstanceOrigin } from './collector.ts'; + +const here=path.dirname(fileURLToPath(import.meta.url));const pkg=path.resolve(here,'..');const repo=path.resolve(pkg,'../..'); +export function loadInstances(config:any){ + if(!config||!Array.isArray(config.instances)||config.instances.length!==2)throw new Error('config must contain exactly two instances'); + for(const raw of config.instances){ + if(!raw||typeof raw!=='object'||typeof raw.url!=='string')throw new Error('invalid collector instance configuration'); + validateInstanceOrigin(raw.url); + if(raw.password||raw.auth?.password||!['none',undefined].includes(raw.auth?.mode))throw new Error('collector instances must be password-free'); + } + const normalized=normalizeConfig(config,{HOST:'127.0.0.1',PORT:'8788'}); + if(normalized.instances.length!==2)throw new Error('config must contain exactly two instances'); + return normalized.instances.map((raw:any,i:number)=>{ + if(raw.auth.mode!=='none'||raw.auth.password)throw new Error(`instance-${i+1} must be password-free`); + return {origin:validateInstanceOrigin(raw.url),alias:`instance-${i+1}`}; + }); +} +async function mapLimit(xs:T[],limit:number,fn:(x:T)=>Promise){const out:R[]=[];let n=0;async function worker(){while(n{const out:string[]=[];for(const e of await readdir(dir,{withFileTypes:true})){const p=path.join(dir,e.name);if(e.isDirectory())out.push(...await allJson(p));else if(e.name.endsWith('.json'))out.push(p);}return out;} +function safeName(s:string){return s.replace(/[^a-zA-Z0-9_-]/g,'-');} +export async function main(argv=process.argv.slice(2)){ + if(argv.length!==1||!['--dry-run','--capture'].includes(argv[0]))throw new Error('usage: collect-readonly-fixtures.ts --dry-run|--capture'); + const config=JSON.parse(await readFile(path.join(repo,'config.json'),'utf8'));const instances=loadInstances(config);const {selected,denied}=selectReadonlyOperations(upstream58e2204Operations); + if(argv[0]==='--dry-run'){for(const op of selected)console.log(`registry ${op.operationId}`);console.log(`selected=${selected.length} denied=${denied.length}`);return;} + const shapePath=path.join(pkg,'src/response-shapes-58e2204.json'); + // Separately reviewed: capture attests this baseline but never creates it. + const shapeBytes=await readFile(shapePath); + const root=path.join(pkg,'src/simadmin');await rm(root,{recursive:true,force:true});await rm(path.join(pkg,'src/manifest.json'),{force:true});await mkdir(root,{recursive:true}); + const jobs=instances.flatMap(instance=>selected.map(op=>({instance,op})));const fixtures=await mapLimit(jobs,2,async({instance,op})=>{const f=await collectOne(instance,op);console.log(`${instance.alias} ${op.operationId} ${f.statusCategory}`);return {f,domain:op.upstreamDomain};}); + for(const {f,domain} of fixtures){const dir=path.join(root,safeName(domain));await mkdir(dir,{recursive:true});await writeFile(path.join(dir,`${f.sourceInstanceAlias}--${f.operationId}.json`),JSON.stringify(f,null,2)+'\n',{flag:'wx'});} + const files=[];const coverage:Record={};for(const full of await allJson(root)){const text=await readFile(full);const rel=path.relative(pkg,full);const domain=path.basename(path.dirname(full));coverage[domain]=(coverage[domain]||0)+1;files.push({path:rel,size:(await stat(full)).size,sha256:createHash('sha256').update(text).digest('hex')});} + files.sort((a,b)=>a.path.localeCompare(b.path));const shapeBaseline={path:'src/response-shapes-58e2204.json',size:shapeBytes.length,sha256:createHash('sha256').update(shapeBytes).digest('hex')};await writeFile(path.join(pkg,'src/manifest.json'),JSON.stringify({schemaVersion:1,upstreamBaseline:'58e2204',realFixtureCount:files.length,syntheticFixtureCount:0,domainCoverage:Object.fromEntries(Object.entries(coverage).sort()),shapeBaseline,files},null,2)+'\n'); +} +if(process.argv[1]===fileURLToPath(import.meta.url))main().catch(()=>{console.error('collector failed');process.exitCode=1;}); diff --git a/packages/test-fixtures/scripts/collector.ts b/packages/test-fixtures/scripts/collector.ts new file mode 100644 index 0000000..e431974 --- /dev/null +++ b/packages/test-fixtures/scripts/collector.ts @@ -0,0 +1,64 @@ +import { redactOperationPayload } from '../src/redactor.ts'; +import { upstream58e2204Operations } from '../../operation-registry/src/upstream-58e2204.ts'; + +export const UPSTREAM_BASELINE='58e2204'; +export const DENY_REASONS:Record={ + '/api/network/operators/scan':'active radio/network scan', + '/api/connectivity':'handler performs active connectivity ping', + '/api/sms/list':'message list can expose body; intentionally not collected', + '/api/sms/conversation':'requires correspondent query and exposes message bodies', + '/api/call/history':'query limit is not encoded in Registry path contract', + '/api/notifications/logs':'query limit is not encoded in Registry path contract', + '/api/notifications/queue':'query limit is not encoded in Registry path contract', + '/api/automation/logs':'query limit is not encoded in Registry path contract', + '/api/device-network/ddns/logs':'no safe limit contract', + '/api/esim/euicc':'query-bearing endpoint omitted', + '/api/esim/profiles':'query-bearing endpoint omitted', +}; +const registryById=new Map(upstream58e2204Operations.map((op:any)=>[op.operationId,op])); +// Capture the complete imported JSON contract before any caller can mutate it. +// Exact identity alone does not protect mutable Registry objects. +const registrySignatures=new Map(upstream58e2204Operations.map((op:any)=>[op.operationId,JSON.stringify(op)])); +function isPrivateLan(host:string){const p=host.split('.').map(Number);return p.length===4&&p.every(n=>Number.isInteger(n)&&n>=0&&n<=255)&&(p[0]===10||(p[0]===172&&p[1]>=16&&p[1]<=31)||(p[0]===192&&p[1]===168));} +export function validateInstanceOrigin(origin:string){ + let u:URL;try{u=new URL(origin);}catch{throw new Error('invalid collector instance origin');} + if(!['http:','https:'].includes(u.protocol)||!isPrivateLan(u.hostname)||u.pathname!=='/'||u.search||u.hash||u.username||u.password)throw new Error('invalid collector instance origin'); + return u.origin; +} +function validatePath(path:string){ + if(typeof path!=='string'||!path.startsWith('/api/')||path.startsWith('//')||path.includes('\\')||/[?#%]/.test(path)||path.includes('//')) throw new Error('unsafe operation path'); + let decoded=path; for(let i=0;i<2;i++){const next=decodeURIComponent(decoded);if(next!==decoded)throw new Error('encoded operation path');decoded=next;} + if(path.split('/').some(x=>x==='.'||x==='..'))throw new Error('dot segment operation path'); + return path; +} +export function validateReadonlyOperation(op:any){ + const exact=registryById.get(op?.operationId); + if(!exact||exact!==op||registrySignatures.get(op?.operationId)!==JSON.stringify(op))throw new Error('operation violates Registry integrity'); + validatePath(op.pathTemplate); + if(op.method!=='GET'||op.riskLevel!=='R0'||/[{}]/.test(op.pathTemplate))throw new Error('operation is not readonly R0'); + if(DENY_REASONS[op.pathTemplate])throw new Error('operation is explicitly denied'); + return op; +} +export function selectReadonlyOperations(registry:any[]){ + const candidates=registry.filter(o=>o.method==='GET'&&o.riskLevel==='R0'&&!/[{}]/.test(o.pathTemplate)); + for(const op of candidates) validatePath(op.pathTemplate); + return {selected:candidates.filter(o=>!DENY_REASONS[o.pathTemplate]).map(validateReadonlyOperation),denied:candidates.filter(o=>DENY_REASONS[o.pathTemplate]).map(o=>({...o,denyReason:DENY_REASONS[o.pathTemplate]}))}; +} +function latency(ms:number,timedOut=false){if(timedOut)return 'timeout';if(ms<250)return '<250ms';if(ms<1000)return '250ms-1s';if(ms<3000)return '1-3s';return '>3s';} +function statusCategory(status:number,isJson:boolean){if(status===401||status===403)return 'auth-required';if(status===404||status===405||status===501)return 'unsupported';if(status>=200&&status<300)return isJson?'success':'non-json';return 'http-error';} +export async function collectOne(instance:{origin:string,alias:string},op:any,transport:any=fetch){ + validateReadonlyOperation(op); + if(!['instance-1','instance-2'].includes(instance?.alias))throw new Error('invalid instance alias'); + const origin=validateInstanceOrigin(instance?.origin); + const requestUrl=new URL(op.pathTemplate,origin); + if(requestUrl.origin!==origin||requestUrl.pathname!==op.pathTemplate||requestUrl.search||requestUrl.hash)throw new Error('unsafe collector request URL'); + const started=Date.now();const controller=new AbortController();const timer=setTimeout(()=>controller.abort(),6000); + const base={schemaVersion:1,upstreamBaseline:UPSTREAM_BASELINE,capturedAt:new Date().toISOString().slice(0,10),sourceInstanceAlias:instance.alias,operationId:op.operationId,method:'GET',pathTemplate:op.pathTemplate,redacted:true}; + try{ + validateReadonlyOperation(op); + const response=await transport(requestUrl,{method:'GET',headers:{accept:'application/json'},body:undefined,credentials:'omit',redirect:'manual',signal:controller.signal}); + const contentType=(response.headers.get('content-type')||'').split(';')[0].trim().toLowerCase()||null;const claimsJson=contentType==='application/json'||contentType?.endsWith('+json'); + let parsedJson=false;let payload:any;if(claimsJson){try{payload=await response.json();parsedJson=true;}catch{payload={error:'invalid-json'};}}else{await response.text();payload={text:'[REDACTED]'};} + return {...base,statusCategory:statusCategory(response.status,parsedJson),httpStatus:response.status,contentType,latencyBucket:latency(Date.now()-started),payload:redactOperationPayload(payload,op)}; + }catch(error:any){if(String(error?.message||'').includes('Registry')||String(error?.message||'').includes('operation'))throw error;const timeout=error?.name==='AbortError';return {...base,statusCategory:timeout?'timeout':'network-error',httpStatus:null,contentType:null,latencyBucket:latency(Date.now()-started,timeout),payload:{error:timeout?'timeout':'network-error'}};}finally{clearTimeout(timer);} +} diff --git a/packages/test-fixtures/src/manifest.json b/packages/test-fixtures/src/manifest.json new file mode 100644 index 0000000..b50b0c6 --- /dev/null +++ b/packages/test-fixtures/src/manifest.json @@ -0,0 +1,418 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "realFixtureCount": 78, + "syntheticFixtureCount": 0, + "domainCoverage": { + "automation": 2, + "calls": 12, + "cellular": 10, + "data-connection": 10, + "device-network": 12, + "device-system": 6, + "instances-auth": 6, + "messages": 2, + "notifications": 2, + "ota": 2, + "radio-lock": 6, + "sim": 2, + "workmode-esim": 6 + }, + "files": [ + { + "path": "src/simadmin/automation/instance-1--getAutomationConfig.json", + "size": 411, + "sha256": "d11fc843d9c120792d5c3c46cc2bfc23a46199fcbbea4d69a5f01f41c246d345" + }, + { + "path": "src/simadmin/automation/instance-2--getAutomationConfig.json", + "size": 411, + "sha256": "7644caa3c9b42e417412fa79c1ffd40ff8d32b0ec5f5c180a74169e2a8fa6f4e" + }, + { + "path": "src/simadmin/calls/instance-1--getCallForwarding.json", + "size": 487, + "sha256": "c4d8cff204ff3abfbca65eae620e575a4f1214df91ee8c48f8c40b98ac4e5b4f" + }, + { + "path": "src/simadmin/calls/instance-1--getCalls.json", + "size": 446, + "sha256": "ad2132947c5ca59820e808fbaedb7ee8f808def626af4241d4665b44e05220bb" + }, + { + "path": "src/simadmin/calls/instance-1--getCallSettings.json", + "size": 796, + "sha256": "64268df9112a40400c40fd38cb629046b66ed007f251895adc6e1464f38df286" + }, + { + "path": "src/simadmin/calls/instance-1--getCallVolume.json", + "size": 483, + "sha256": "816e75f1356da18712a12c1d9e4e65b949349590c13e79b16146a2e55e3de112" + }, + { + "path": "src/simadmin/calls/instance-1--getImsStatus.json", + "size": 472, + "sha256": "7c38e2a3afe05aa68df1bc5d1747d556e7d623e183dddfd5f79093e566602b33" + }, + { + "path": "src/simadmin/calls/instance-1--getVoicemailStatus.json", + "size": 490, + "sha256": "61066e2ae5122adaeed410a3f628872cbb475df9b6d1fa9fb74165f6a102216b" + }, + { + "path": "src/simadmin/calls/instance-2--getCallForwarding.json", + "size": 487, + "sha256": "8a20cd0ad05764ed520c2d484ac092a30b03beccdcc00b9e23d795a8e35c5087" + }, + { + "path": "src/simadmin/calls/instance-2--getCalls.json", + "size": 446, + "sha256": "3947b6a4f96e76515ec2fe0d2778eaea12dca468a1ccf6f642c252a2d3befe15" + }, + { + "path": "src/simadmin/calls/instance-2--getCallSettings.json", + "size": 796, + "sha256": "ced02cdde68e46fdce377312a3f13b146a71e986a983ad826f23d3e654937082" + }, + { + "path": "src/simadmin/calls/instance-2--getCallVolume.json", + "size": 483, + "sha256": "46b753951be5cf88602cd757078665a4569a9f6af29f5652d8a2589918cbd1bc" + }, + { + "path": "src/simadmin/calls/instance-2--getImsStatus.json", + "size": 472, + "sha256": "cc0fe42dc6367061cb6655fd7eff2a080b9f4c7656a4f6085a2675b7b015c6c6" + }, + { + "path": "src/simadmin/calls/instance-2--getVoicemailStatus.json", + "size": 490, + "sha256": "09444cd4b71f10414a481e31c8f05199b4cff1b5388ac3223279b3e7507859cb" + }, + { + "path": "src/simadmin/cellular/instance-1--getCells.json", + "size": 859, + "sha256": "939806fafaa6e377ea163d8d1c4b2a471a354e27ede421e9086b01493fd99354" + }, + { + "path": "src/simadmin/cellular/instance-1--getLocationCellInfo.json", + "size": 1005, + "sha256": "b1802511d2fb18040923185cf71c5419a9553fa60107e1fad04146f3cb9fe450" + }, + { + "path": "src/simadmin/cellular/instance-1--getNetwork.json", + "size": 631, + "sha256": "8fb2a9b1c17402d2f21912ff66b66291de12f8fd2c9b9e43058370c7f94f2671" + }, + { + "path": "src/simadmin/cellular/instance-1--getNetworkOperators.json", + "size": 714, + "sha256": "73da8d7763fd82530a51c6fce5c0ff924a1778d71861c4fd9f29d061609d1c7b" + }, + { + "path": "src/simadmin/cellular/instance-1--getNetworkSignalStrength.json", + "size": 486, + "sha256": "2999ddf03251b6b896c54e7d70eb37f5d9c96ea89f271174a37ddd50eb0765a3" + }, + { + "path": "src/simadmin/cellular/instance-2--getCells.json", + "size": 859, + "sha256": "5c6bbf23e612db363e728f8ed344a1b8fcb7d3a35adab14e6cd2eaac1debf92b" + }, + { + "path": "src/simadmin/cellular/instance-2--getLocationCellInfo.json", + "size": 1005, + "sha256": "dc1b0a6f59951c23fae19ef09b60d9dcfd7b369f0aab2b9c37a036ea9a3e45ad" + }, + { + "path": "src/simadmin/cellular/instance-2--getNetwork.json", + "size": 631, + "sha256": "ff187f0305c84ff13c68cdaa8b5d2f0edc85ba08403d61a484c76244c106d583" + }, + { + "path": "src/simadmin/cellular/instance-2--getNetworkOperators.json", + "size": 714, + "sha256": "6d6259f5560f2abe67f6afaaa98c84aeb6fcf6b0cccd093f4ef261ebd91d5043" + }, + { + "path": "src/simadmin/cellular/instance-2--getNetworkSignalStrength.json", + "size": 486, + "sha256": "d7362c1857f457831b8284375a288ff38109d6458fbd27f204e5fc77698ccbdc" + }, + { + "path": "src/simadmin/data-connection/instance-1--getAirplaneMode.json", + "size": 514, + "sha256": "5aa56c71ca7b7fb61ae32e97aaa8fa2a5043a0ae2a6847667a37dba4f1353e75" + }, + { + "path": "src/simadmin/data-connection/instance-1--getApn.json", + "size": 761, + "sha256": "daa957d911d712c44cfd0daa6def5cd094bf2ed9a25e8345a063169cd29b6b85" + }, + { + "path": "src/simadmin/data-connection/instance-1--getBasebandRestartStatus.json", + "size": 507, + "sha256": "9eb8f1fe2d183b2ce0ce1a4e8db5fbd0173b874c2a921cf483ca41f0801540bf" + }, + { + "path": "src/simadmin/data-connection/instance-1--getData.json", + "size": 451, + "sha256": "250fe59ff07a353596fcfc286b90ac9be6cd59dfe1f115a17bb52fba5eef96f5" + }, + { + "path": "src/simadmin/data-connection/instance-1--getRoaming.json", + "size": 493, + "sha256": "3793690eea13d9ec58e01aa2efdce29132e6cc47c470f8e9ef0c3906c33e2ec6" + }, + { + "path": "src/simadmin/data-connection/instance-2--getAirplaneMode.json", + "size": 514, + "sha256": "6edc530b74bb390ef329cf75739bbb7a4043d8007c44af34b2a89c2f4f5b985c" + }, + { + "path": "src/simadmin/data-connection/instance-2--getApn.json", + "size": 761, + "sha256": "0a4e0e6e21707910646613722ad1a52348a3cfaf178017d9100293fb116b5b8f" + }, + { + "path": "src/simadmin/data-connection/instance-2--getBasebandRestartStatus.json", + "size": 507, + "sha256": "7656ea60e5f4fa138e968da910e2f536f84fcf40001d8cdcbf8472d228297979" + }, + { + "path": "src/simadmin/data-connection/instance-2--getData.json", + "size": 451, + "sha256": "c79d7a33478229c779ea221f2d8d824f3302e9c6d577eadef2640676f8bfb12b" + }, + { + "path": "src/simadmin/data-connection/instance-2--getRoaming.json", + "size": 493, + "sha256": "25d80ea1f2b4265a9306267c8b9182ce5c73dc9c82fd0c5faaf4e955fa1d2111" + }, + { + "path": "src/simadmin/device-network/instance-1--getDeviceNetworkDdnsConfig.json", + "size": 1247, + "sha256": "a196f88ca3683bcb88cb40043e2073f65f8a467de384a903031439cb9af8da5b" + }, + { + "path": "src/simadmin/device-network/instance-1--getDeviceNetworkDdnsStatus.json", + "size": 657, + "sha256": "85f4a794f3bf0dac8c1fbbc69e2054f9b1c9a8ba2d36e4d76e0dd1dd8f080849" + }, + { + "path": "src/simadmin/device-network/instance-1--getDeviceNetworkWlanProfiles.json", + "size": 705, + "sha256": "fe06ef527f06715c6aace36bb1a4f15e553f46ffe30eaa9e91d374c3ac50d7b3" + }, + { + "path": "src/simadmin/device-network/instance-1--getDeviceNetworkWlanStatus.json", + "size": 862, + "sha256": "c10e9bda965951db993a647122d9eef311cf65d92f12432942a0050439e0bc3e" + }, + { + "path": "src/simadmin/device-network/instance-1--getNetworkConnectionAddresses.json", + "size": 654, + "sha256": "ef8adddeb80fba7380ccd7f7aa8cfe3d923dd3cd6b784105bd7379e0de3b72ba" + }, + { + "path": "src/simadmin/device-network/instance-1--getNetworkInterfaces.json", + "size": 7178, + "sha256": "e002a51e824fc940eae82d9853bc4dda70c43ccfadaf46165f18511406c70f34" + }, + { + "path": "src/simadmin/device-network/instance-2--getDeviceNetworkDdnsConfig.json", + "size": 1247, + "sha256": "52a0844767bfe4eaa1bbfa416f12a33c19e32d32a6f3ee81603399655c48fe87" + }, + { + "path": "src/simadmin/device-network/instance-2--getDeviceNetworkDdnsStatus.json", + "size": 657, + "sha256": "95818e5300b7b2d4a863c63c470e136c6c1c632825e0affec9fa664bd905decb" + }, + { + "path": "src/simadmin/device-network/instance-2--getDeviceNetworkWlanProfiles.json", + "size": 703, + "sha256": "1f72f32f15c333d3252751f0c223849071e68dd879b7d76a543c2e14d18e91cd" + }, + { + "path": "src/simadmin/device-network/instance-2--getDeviceNetworkWlanStatus.json", + "size": 862, + "sha256": "b0ba613f078e56cc6bf4d9e7736abaf6a941b6f1c4646527e1194da3775d3f7d" + }, + { + "path": "src/simadmin/device-network/instance-2--getNetworkConnectionAddresses.json", + "size": 654, + "sha256": "0b69ebe7267a762ef68ce96f692fe85097cc918588cb138cb5ad81e03885cbae" + }, + { + "path": "src/simadmin/device-network/instance-2--getNetworkInterfaces.json", + "size": 7178, + "sha256": "9d5630a639da04e3b97bdd3c8bb45324aa30689e63e483507cb4af19750eed0f" + }, + { + "path": "src/simadmin/device-system/instance-1--getDevice.json", + "size": 606, + "sha256": "521824ff36c00840077ef62b4b4b682804ee631df92f8d5849f8e6b7c250508f" + }, + { + "path": "src/simadmin/device-system/instance-1--getStats.json", + "size": 2571, + "sha256": "3677b4c77941ddf7da7c1c6f73bf923adcbbda413d0327516a39c66cbb9f959f" + }, + { + "path": "src/simadmin/device-system/instance-1--getStatsCpu.json", + "size": 2070, + "sha256": "a7b1303f8d70dfb7c6ce078c1f1cd8a55cc554d05400f8948adccc6fc2bd4cd2" + }, + { + "path": "src/simadmin/device-system/instance-2--getDevice.json", + "size": 604, + "sha256": "a19499a4cd0f5c5022e167d9c5871c367f37f6292e17bc03dc3d40c9ccef6663" + }, + { + "path": "src/simadmin/device-system/instance-2--getStats.json", + "size": 2568, + "sha256": "66394c29165b906613d4f083e557deecaad26b080ff94080b990555991ae1018" + }, + { + "path": "src/simadmin/device-system/instance-2--getStatsCpu.json", + "size": 2070, + "sha256": "427fad157dabc8ac1227db4f9114a83d45da11aefc9d8f4a7065de749959dc0c" + }, + { + "path": "src/simadmin/instances-auth/instance-1--getAuthSettings.json", + "size": 403, + "sha256": "fce6c71a20f6e99744d40ebda8c570f5dd3dffe475ce25ce08fb3eff859339fc" + }, + { + "path": "src/simadmin/instances-auth/instance-1--getAuthStatus.json", + "size": 399, + "sha256": "23eba110da227cba6112f2ad848c980f94f69597e0697a08290d134771f40c91" + }, + { + "path": "src/simadmin/instances-auth/instance-1--getHealth.json", + "size": 478, + "sha256": "000ce1f086ba62a206ca0fdff3a157524e49c6d2879ef21e6add08826cf7f2ad" + }, + { + "path": "src/simadmin/instances-auth/instance-2--getAuthSettings.json", + "size": 784, + "sha256": "f22ad6b7b13ccdd279c9e26722a0f64395a12c184fc26429ca365ab761789f9b" + }, + { + "path": "src/simadmin/instances-auth/instance-2--getAuthStatus.json", + "size": 809, + "sha256": "2860f468c3da7d390bd30bdd184517da6d1272b06ecbdc472031fb6206a22f1c" + }, + { + "path": "src/simadmin/instances-auth/instance-2--getHealth.json", + "size": 478, + "sha256": "9d7120b284db3008d00439f5e117c287336a269be4835e50db89a7f0806ec503" + }, + { + "path": "src/simadmin/messages/instance-1--getSmsStats.json", + "size": 499, + "sha256": "086e7bb4d33a4ce66e86eb781ed5be1cb63ba01f95170befc0ddec3db690ba7c" + }, + { + "path": "src/simadmin/messages/instance-2--getSmsStats.json", + "size": 545, + "sha256": "702bb29db443164ac95a2fb66433749b9b8d8bae4cb63de17187043a26b4cf09" + }, + { + "path": "src/simadmin/notifications/instance-1--getNotificationsConfig.json", + "size": 4857, + "sha256": "872b49d3a8c38d7f87012dad212b3fab2c6e4a8c5949c2284140e36d8a0e81b0" + }, + { + "path": "src/simadmin/notifications/instance-2--getNotificationsConfig.json", + "size": 2377, + "sha256": "8586332d14c7e2f9c807c5e62f3c865f0b412af17357f86aff62919bf9021052" + }, + { + "path": "src/simadmin/ota/instance-1--getOtaStatus.json", + "size": 539, + "sha256": "72b7d0792f49d1f4aabf0c59c80cae9259f8ad280f0f5db15875906476cbf294" + }, + { + "path": "src/simadmin/ota/instance-2--getOtaStatus.json", + "size": 539, + "sha256": "e5d0449dedbdea5f0bc304b4a45a10da0d773955c4408a958ffb10872c9044c4" + }, + { + "path": "src/simadmin/radio-lock/instance-1--getBandLock.json", + "size": 864, + "sha256": "c24e823e8c3f5ff40451fb6e1ac3a46189072ca17b05d7e16d93008ec80cd06d" + }, + { + "path": "src/simadmin/radio-lock/instance-1--getCellLock.json", + "size": 837, + "sha256": "e53efdbd885ac11899ac5fe7b66d7174fb6ad3c8eaefaee3c2998d47dff41567" + }, + { + "path": "src/simadmin/radio-lock/instance-1--getRadioMode.json", + "size": 573, + "sha256": "35a728a1b34dccdbf8e6a8b2eb8ea43d3986ceb239406e2f31783f2095233368" + }, + { + "path": "src/simadmin/radio-lock/instance-2--getBandLock.json", + "size": 864, + "sha256": "5b0172f1b6d39d046a9a1be766e988aed921c990cb15ba6863ce3f302f3a21c0" + }, + { + "path": "src/simadmin/radio-lock/instance-2--getCellLock.json", + "size": 837, + "sha256": "4bb27d837265d3f9e1b2bd8ccf247af6bc3dab17d7bb65e10af7bf18359073da" + }, + { + "path": "src/simadmin/radio-lock/instance-2--getRadioMode.json", + "size": 573, + "sha256": "7ad89ba63089b98763da4bc6e544188356661dc7c1710e73eb047af906e2685c" + }, + { + "path": "src/simadmin/sim/instance-1--getSim.json", + "size": 712, + "sha256": "3d98909a13f3801e63ac0d801998dc91462accfbf3e11c78a3322723475c9743" + }, + { + "path": "src/simadmin/sim/instance-2--getSim.json", + "size": 709, + "sha256": "9edba55b3592554831913ab544713c4e768267ae3f054d48e4d0bf0b61ffa746" + }, + { + "path": "src/simadmin/workmode-esim/instance-1--getEsimConfig.json", + "size": 399, + "sha256": "deb99d35aa9fca3149f5554d39bcaa6cd76046b3d48b9d8f6d8faa5050ac5ee8" + }, + { + "path": "src/simadmin/workmode-esim/instance-1--getEsimLpacStatus.json", + "size": 476, + "sha256": "045e57c7b75fc3e1edc03ffa025997dc03e9d95dff0967769389c8682df088dd" + }, + { + "path": "src/simadmin/workmode-esim/instance-1--getWorkMode.json", + "size": 489, + "sha256": "b8c0f72a5e1f260d74e1f487f14ed6b948f0f166e33d7379eb7ec6e4b76bac72" + }, + { + "path": "src/simadmin/workmode-esim/instance-2--getEsimConfig.json", + "size": 399, + "sha256": "09c46f91077fbb55491139d3d8c1a7e779835a056a8ed6cd872dbdcb8799f678" + }, + { + "path": "src/simadmin/workmode-esim/instance-2--getEsimLpacStatus.json", + "size": 476, + "sha256": "3b2fde972698b63efbdd7ef63199443fcb7d2ef682f41c6efa2c8078aaf6b336" + }, + { + "path": "src/simadmin/workmode-esim/instance-2--getWorkMode.json", + "size": 489, + "sha256": "2faeb2d4b715944403bde8b2732eb531779056ffc22fb6a1ee6ff3d88124ae10" + } + ], + "shapeBaseline": { + "path": "src/response-shapes-58e2204.json", + "size": 155410, + "sha256": "812d5aebae34e5c8550a47ea6bada6a59645c224ee1dec3a82c8d5e28fa14163" + } +} diff --git a/packages/test-fixtures/src/redactor.ts b/packages/test-fixtures/src/redactor.ts new file mode 100644 index 0000000..73f63de --- /dev/null +++ b/packages/test-fixtures/src/redactor.ts @@ -0,0 +1,82 @@ +const SECRET_KEY = /(?:password|passwd|credential|api[_-]?key|access[_-]?(?:key|token|secret|id)|device[_-]?key|private[_-]?key|pin|puk|username|(?:^|[_-])user(?:$|[_-])|account|serial|revision|(?:^|[_-])path(?:$|[_-])|template|token|secret|cookie|authorization|content|body|confirmation[_-]?code)/i; +const STRUCTURED_KEY = /^(?:config)$/i; +const LOCATION_KEY = /^(?:lat(?:itude)?|lon(?:gitude)?|cell_?id|cid|lac|tac|pci|e?nb|gnb)$/i; +const FINGERPRINT_KEY = /^(?:uptime|traffic|temperature|.*(?:rx|tx)[_-]?(?:bytes|packets)|.*percent|(?:created|updated|captured)?_?at|timestamp|time)$/i; +const SAFE_BOOLEAN_KEY = /(?:phone_number|sms_center)_is_manual$/i; +const PHONE_KEY = /(?:phone|msisdn|recipient|number|smsc|sms_center)/i; +const IDENTIFIER_KEY = /(?:iccid|imsi|imei|eid|matching_id)/i; +const ADDRESS_KEY = /(?:ssid|bssid|mac|(?:^|_)(?:ip|address)(?:_|$)|hostname|host|url|webhook)/i; + +export function typedRedact(value:any):any { + if(Array.isArray(value)) return value.map(typedRedact); + if(value && typeof value==='object') return Object.fromEntries(Object.entries(value).map(([k,v])=>[k,typedRedact(v)])); + if(typeof value==='string') return '[REDACTED]'; + if(typeof value==='number') return 0; + if(typeof value==='boolean') return false; + return value; +} + +function looksHighEntropy(s:string){ + if(s.length<16 || /\s/.test(s)) return false; + const classes=[/[a-z]/,/[A-Z]/,/\d/,/[^A-Za-z0-9]/].filter(r=>r.test(s)).length; + return classes>=3 || (classes>=2 && new Set(s).size>=12); +} +function unsafeString(s:string){ + return /https?:\/\//i.test(s) || /(?:^|\s|["'=])(?:[a-z0-9-]+\.)+[a-z]{2,}(?::\d+)?(?:\/\S*)?/i.test(s) || + /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i.test(s) || /(?:[0-9a-f]{2}:){5}[0-9a-f]{2}/i.test(s) || + /(?:^|[^\w])(?:[0-9a-f]{0,4}:){2,}[0-9a-f:%]+(?:$|[^\w])/i.test(s) || /\b(?:\d{1,3}\.){3}\d{1,3}\b/.test(s) || + /(?:^|\D)\+?\d(?:[ ()-]*\d){7,}(?:$|\D)/.test(s) || /(?:\d[ -]){6,}\d/.test(s) || + /(?:^|\s)(?:\/Users\/|\/home\/|\/var\/|\/etc\/|[A-Za-z]:\\)\S+/i.test(s) || + /\b(?:token|user(?:name)?|account|path|url|host)\s*[=:]\s*\S+/i.test(s) || /\b(?:AKIA|ASIA)[A-Z0-9]{12,}\b/.test(s) || looksHighEntropy(s); +} + +class Context { + value(value:any,key='',force=false):any { + if(SAFE_BOOLEAN_KEY.test(key) && typeof value==='boolean') return value; + if(SECRET_KEY.test(key) || LOCATION_KEY.test(key) || FINGERPRINT_KEY.test(key)) return typedRedact(value); + if(STRUCTURED_KEY.test(key)) force=true; + if(PHONE_KEY.test(key)||IDENTIFIER_KEY.test(key)||ADDRESS_KEY.test(key)) return typedRedact(value); + if(Array.isArray(value)) return value.map(v=>this.value(v,'',force)); + if(value && typeof value==='object') return Object.fromEntries(Object.entries(value).map(([k,v])=>[k,this.value(v,k,force)])); + if(force) return typedRedact(value); + if(typeof value==='string'){ + const t=value.trim(); + if((t.startsWith('{')&&t.endsWith('}'))||(t.startsWith('[')&&t.endsWith(']'))){try{return JSON.stringify(this.value(JSON.parse(value)));}catch{}} + return unsafeString(value)?'[REDACTED]':value; + } + if(typeof value==='number' && Number.isInteger(value) && Math.abs(value)>=100_000_000) return 0; + return value; + } +} + +export function parseResponseSensitivePath(path:string):string[] { + if(typeof path!=='string'||!path.startsWith('$.response')) throw new Error('unsupported response sensitive path'); + const rest=path.slice('$.response'.length); + if(!rest) return []; + if(!/^(?:\.[A-Za-z0-9_-]+|\[\*\])+$/.test(rest)) throw new Error('unsupported response sensitive path'); + return [...rest.matchAll(/\.([A-Za-z0-9_-]+)|\[\*\]/g)].map(m=>m[1]||'*'); +} +export function applySensitivePath(node:any,parts:string[],index=0):number { + if(index===parts.length) return 0; + const part=parts[index]; + if(part==='*'){ + if(!Array.isArray(node)) return 0; + if(index===parts.length-1){for(let i=0;in+applySensitivePath(item,parts,index+1),0); + } + if(!node||typeof node!=='object'||!(part in node)) return 0; + if(index===parts.length-1){node[part]=typedRedact(node[part]);return 1;} + return applySensitivePath(node[part],parts,index+1); +} +export function redactOperationPayload(value:T,operation:any):T { + const clone=structuredClone(value); + for(const field of operation?.sensitiveFields||[]){ + if(field?.direction!=='response') continue; + const parts=parseResponseSensitivePath(field.path); + // The decoded HTTP body corresponds to $.response; parts are body-relative + // (normally beginning with `data`), so do not add another response wrapper. + applySensitivePath(clone,parts); + } + return new Context().value(clone) as T; +} +export function redact(value:T):T { return new Context().value(value) as T; } diff --git a/packages/test-fixtures/src/response-shapes-58e2204.json b/packages/test-fixtures/src/response-shapes-58e2204.json new file mode 100644 index 0000000..16c5f5e --- /dev/null +++ b/packages/test-fixtures/src/response-shapes-58e2204.json @@ -0,0 +1,5702 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "shapes": { + "instance-1::getAirplaneMode": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "enabled": { + "type": "boolean" + }, + "online": { + "type": "boolean" + }, + "powered": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getApn": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "contexts": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "active": { + "type": "boolean" + }, + "apn": { + "type": "string" + }, + "auth_method": { + "type": "string" + }, + "context_type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "password": { + "type": "string" + }, + "path": { + "type": "string" + }, + "protocol": { + "type": "string" + }, + "username": { + "type": "string" + } + } + } + ] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getAuthSettings": { + "type": "object", + "keys": { + "text": { + "type": "string" + } + } + }, + "instance-1::getAuthStatus": { + "type": "object", + "keys": { + "text": { + "type": "string" + } + } + }, + "instance-1::getAutomationConfig": { + "type": "object", + "keys": { + "text": { + "type": "string" + } + } + }, + "instance-1::getBandLock": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "locked": { + "type": "boolean" + }, + "lte_fdd_bands": { + "type": "array", + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "lte_tdd_bands": { + "type": "array", + "items": [] + }, + "nr_fdd_bands": { + "type": "array", + "items": [] + }, + "nr_tdd_bands": { + "type": "array", + "items": [] + }, + "supported_lte_fdd_bands": { + "type": "array", + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "supported_lte_tdd_bands": { + "type": "array", + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "supported_nr_fdd_bands": { + "type": "array", + "items": [] + }, + "supported_nr_tdd_bands": { + "type": "array", + "items": [] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getBasebandRestartStatus": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "running": { + "type": "boolean" + }, + "steps": { + "type": "array", + "items": [] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getCallForwarding": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getCallSettings": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "called_line_presentation": { + "type": "string" + }, + "calling_line_presentation": { + "type": "string" + }, + "calling_line_restriction": { + "type": "string" + }, + "calling_name_presentation": { + "type": "string" + }, + "connected_line_presentation": { + "type": "string" + }, + "connected_line_restriction": { + "type": "string" + }, + "hide_caller_id": { + "type": "string" + }, + "voice_call_waiting": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getCallVolume": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getCalls": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "calls": { + "type": "array", + "items": [] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getCellLock": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "any_locked": { + "type": "boolean" + }, + "rat_status": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "arfcn": { + "type": "null" + }, + "enabled": { + "type": "boolean" + }, + "lock_type": { + "type": "number" + }, + "pci": { + "type": "null" + }, + "rat": { + "type": "number" + }, + "rat_name": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "arfcn": { + "type": "null" + }, + "enabled": { + "type": "boolean" + }, + "lock_type": { + "type": "number" + }, + "pci": { + "type": "null" + }, + "rat": { + "type": "number" + }, + "rat_name": { + "type": "string" + } + } + } + ] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getCells": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "cells": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "arfcn": { + "type": "string" + }, + "band": { + "type": "string" + }, + "cell_id": { + "type": "number" + }, + "earfcn": { + "type": "string" + }, + "is_serving": { + "type": "boolean" + }, + "pci": { + "type": "string" + }, + "rsrp": { + "type": "string" + }, + "rsrq": { + "type": "string" + }, + "sinr": { + "type": "string" + }, + "tech": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + ] + }, + "serving_cell": { + "type": "object", + "keys": { + "cell_id": { + "type": "number" + }, + "tac": { + "type": "number" + }, + "tech": { + "type": "string" + } + } + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getData": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "active": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getDevice": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "imei": { + "type": "string" + }, + "manufacturer": { + "type": "string" + }, + "model": { + "type": "string" + }, + "online": { + "type": "boolean" + }, + "powered": { + "type": "boolean" + }, + "revision": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getDeviceNetworkDdnsConfig": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "access_id": { + "type": "string" + }, + "access_secret": { + "type": "string" + }, + "access_secret_set": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "interval_seconds": { + "type": "number" + }, + "ipv4": { + "type": "object", + "keys": { + "domains": { + "type": "array", + "items": [] + }, + "enabled": { + "type": "boolean" + }, + "get_type": { + "type": "string" + }, + "interface_name": { + "type": "string" + }, + "urls": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + } + } + }, + "ipv6": { + "type": "object", + "keys": { + "domains": { + "type": "array", + "items": [] + }, + "enabled": { + "type": "boolean" + }, + "get_type": { + "type": "string" + }, + "interface_name": { + "type": "string" + }, + "urls": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + } + } + }, + "provider": { + "type": "string" + }, + "ttl": { + "type": "number" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getDeviceNetworkDdnsStatus": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "enabled": { + "type": "boolean" + }, + "last_ipv4": { + "type": "null" + }, + "last_ipv6": { + "type": "null" + }, + "last_message": { + "type": "null" + }, + "last_sync_at": { + "type": "null" + }, + "provider": { + "type": "string" + }, + "running": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getDeviceNetworkWlanProfiles": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "profiles": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "active": { + "type": "boolean" + }, + "auto_join": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "interface_name": { + "type": "string" + }, + "ssid": { + "type": "string" + }, + "uuid": { + "type": "string" + } + } + } + ] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getDeviceNetworkWlanStatus": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "available": { + "type": "boolean" + }, + "connected": { + "type": "boolean" + }, + "connection_id": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hardware_enabled": { + "type": "boolean" + }, + "interface_name": { + "type": "string" + }, + "ipv4_addresses": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + }, + "ipv4_gateway": { + "type": "string" + }, + "ipv6_addresses": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "ssid": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getEsimConfig": { + "type": "object", + "keys": { + "text": { + "type": "string" + } + } + }, + "instance-1::getEsimLpacStatus": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getHealth": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "platform": { + "type": "string" + }, + "status": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "instance-1::getImsStatus": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getLocationCellInfo": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "available": { + "type": "boolean" + }, + "cell_info": { + "type": "object", + "keys": { + "arfcn": { + "type": "number" + }, + "cid": { + "type": "number" + }, + "lac": { + "type": "number" + }, + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + }, + "pci": { + "type": "number" + }, + "radio_type": { + "type": "string" + }, + "rsrq": { + "type": "number" + }, + "signal_strength": { + "type": "number" + } + } + }, + "cells": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "arfcn": { + "type": "number" + }, + "cid": { + "type": "number" + }, + "lac": { + "type": "number" + }, + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + }, + "pci": { + "type": "number" + }, + "radio_type": { + "type": "string" + }, + "rsrq": { + "type": "number" + }, + "signal_strength": { + "type": "number" + } + } + } + ] + }, + "neighbor_cells": { + "type": "array", + "items": [] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getNetwork": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + }, + "operator_name": { + "type": "string" + }, + "registration_status": { + "type": "string" + }, + "signal_strength": { + "type": "number" + }, + "technology_preference": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getNetworkConnectionAddresses": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "ipv4": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + }, + "ipv4_interface": { + "type": "string" + }, + "ipv6": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "ipv6_interface": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getNetworkInterfaces": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "interfaces": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + } + ] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mac_address": { + "type": "string" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mac_address": { + "type": "string" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mac_address": { + "type": "string" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + } + ] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mac_address": { + "type": "string" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + } + ] + }, + "total_count": { + "type": "number" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getNetworkOperators": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "operators": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + }, + "name": { + "type": "string" + }, + "path": { + "type": "string" + }, + "status": { + "type": "string" + }, + "technologies": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + } + } + } + ] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getNetworkSignalStrength": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "strength": { + "type": "number" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getNotificationsConfig": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "bark": { + "type": "object", + "keys": { + "auto_copy": { + "type": "boolean" + }, + "call_template": { + "type": "string" + }, + "click_url": { + "type": "string" + }, + "copy": { + "type": "string" + }, + "ddns_template": { + "type": "string" + }, + "device_key": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_calls": { + "type": "boolean" + }, + "forward_ddns": { + "type": "boolean" + }, + "forward_sms": { + "type": "boolean" + }, + "forward_updates": { + "type": "boolean" + }, + "group": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "level": { + "type": "string" + }, + "save_history": { + "type": "boolean" + }, + "server_url": { + "type": "string" + }, + "sms_template": { + "type": "string" + }, + "sound": { + "type": "string" + }, + "title_template": { + "type": "string" + }, + "update_template": { + "type": "string" + } + } + }, + "dingtalk_app": { + "type": "object", + "keys": { + "app_key": { + "type": "string" + }, + "app_secret": { + "type": "string" + }, + "call_template": { + "type": "string" + }, + "ddns_template": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_calls": { + "type": "boolean" + }, + "forward_ddns": { + "type": "boolean" + }, + "forward_sms": { + "type": "boolean" + }, + "forward_updates": { + "type": "boolean" + }, + "msg_key": { + "type": "string" + }, + "open_conversation_id": { + "type": "string" + }, + "robot_code": { + "type": "string" + }, + "sms_template": { + "type": "string" + }, + "update_template": { + "type": "string" + } + } + }, + "dingtalk_robot": { + "type": "object", + "keys": { + "access_token": { + "type": "string" + }, + "at_all": { + "type": "boolean" + }, + "at_mobiles": { + "type": "string" + }, + "call_template": { + "type": "string" + }, + "ddns_template": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_calls": { + "type": "boolean" + }, + "forward_ddns": { + "type": "boolean" + }, + "forward_sms": { + "type": "boolean" + }, + "forward_updates": { + "type": "boolean" + }, + "secret": { + "type": "string" + }, + "sms_template": { + "type": "string" + }, + "update_template": { + "type": "string" + }, + "webhook_url": { + "type": "string" + } + } + }, + "feishu_robot": { + "type": "object", + "keys": { + "call_template": { + "type": "string" + }, + "ddns_template": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_calls": { + "type": "boolean" + }, + "forward_ddns": { + "type": "boolean" + }, + "forward_sms": { + "type": "boolean" + }, + "forward_updates": { + "type": "boolean" + }, + "secret": { + "type": "string" + }, + "sms_template": { + "type": "string" + }, + "token": { + "type": "string" + }, + "update_template": { + "type": "string" + }, + "webhook_url": { + "type": "string" + } + } + }, + "pushplus": { + "type": "object", + "keys": { + "call_template": { + "type": "string" + }, + "callback_url": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "ddns_template": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_calls": { + "type": "boolean" + }, + "forward_ddns": { + "type": "boolean" + }, + "forward_sms": { + "type": "boolean" + }, + "forward_updates": { + "type": "boolean" + }, + "option": { + "type": "string" + }, + "sms_template": { + "type": "string" + }, + "template": { + "type": "string" + }, + "title_template": { + "type": "string" + }, + "token": { + "type": "string" + }, + "topic": { + "type": "string" + }, + "update_template": { + "type": "string" + } + } + }, + "telegram": { + "type": "object", + "keys": { + "bot_token": { + "type": "string" + }, + "call_template": { + "type": "string" + }, + "chat_id": { + "type": "string" + }, + "ddns_template": { + "type": "string" + }, + "disable_web_page_preview": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "forward_calls": { + "type": "boolean" + }, + "forward_ddns": { + "type": "boolean" + }, + "forward_sms": { + "type": "boolean" + }, + "forward_updates": { + "type": "boolean" + }, + "parse_mode": { + "type": "string" + }, + "sms_template": { + "type": "string" + }, + "update_template": { + "type": "string" + } + } + }, + "webhook": { + "type": "object", + "keys": { + "call_template": { + "type": "string" + }, + "ddns_template": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_calls": { + "type": "boolean" + }, + "forward_ddns": { + "type": "boolean" + }, + "forward_sms": { + "type": "boolean" + }, + "forward_updates": { + "type": "boolean" + }, + "headers": { + "type": "object", + "keys": {} + }, + "secret": { + "type": "string" + }, + "sms_template": { + "type": "string" + }, + "update_template": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "wecom_app": { + "type": "object", + "keys": { + "agent_id": { + "type": "string" + }, + "call_template": { + "type": "string" + }, + "corp_id": { + "type": "string" + }, + "ddns_template": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_calls": { + "type": "boolean" + }, + "forward_ddns": { + "type": "boolean" + }, + "forward_sms": { + "type": "boolean" + }, + "forward_updates": { + "type": "boolean" + }, + "safe": { + "type": "boolean" + }, + "secret": { + "type": "string" + }, + "sms_template": { + "type": "string" + }, + "to_party": { + "type": "string" + }, + "to_tag": { + "type": "string" + }, + "to_user": { + "type": "string" + }, + "update_template": { + "type": "string" + } + } + }, + "wecom_robot": { + "type": "object", + "keys": { + "call_template": { + "type": "string" + }, + "ddns_template": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_calls": { + "type": "boolean" + }, + "forward_ddns": { + "type": "boolean" + }, + "forward_sms": { + "type": "boolean" + }, + "forward_updates": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "sms_template": { + "type": "string" + }, + "update_template": { + "type": "string" + }, + "webhook_url": { + "type": "string" + } + } + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getOtaStatus": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "current_commit": { + "type": "string" + }, + "current_version": { + "type": "string" + }, + "pending_update": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getRadioMode": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "mode": { + "type": "string" + }, + "supported_modes": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "technology_preference": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getRoaming": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "is_roaming": { + "type": "boolean" + }, + "roaming_allowed": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getSim": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "iccid": { + "type": "string" + }, + "imsi": { + "type": "string" + }, + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + }, + "phone_number_is_manual": { + "type": "boolean" + }, + "phone_numbers": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + }, + "present": { + "type": "boolean" + }, + "sms_center": { + "type": "string" + }, + "sms_center_is_manual": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getSmsStats": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "incoming": { + "type": "number" + }, + "outgoing": { + "type": "number" + }, + "total": { + "type": "number" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getStats": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "cpu_load": { + "type": "object", + "keys": { + "core_count": { + "type": "number" + }, + "load_15min": { + "type": "number" + }, + "load_1min": { + "type": "number" + }, + "load_5min": { + "type": "number" + }, + "load_percent": { + "type": "number" + } + } + }, + "disk": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "available_bytes": { + "type": "number" + }, + "fs_type": { + "type": "string" + }, + "mount_point": { + "type": "string" + }, + "total_bytes": { + "type": "number" + }, + "used_bytes": { + "type": "number" + }, + "used_percent": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "available_bytes": { + "type": "number" + }, + "fs_type": { + "type": "string" + }, + "mount_point": { + "type": "string" + }, + "total_bytes": { + "type": "number" + }, + "used_bytes": { + "type": "number" + }, + "used_percent": { + "type": "number" + } + } + } + ] + }, + "memory": { + "type": "object", + "keys": { + "available_bytes": { + "type": "number" + }, + "buffers_bytes": { + "type": "number" + }, + "cached_bytes": { + "type": "number" + }, + "total_bytes": { + "type": "number" + }, + "used_bytes": { + "type": "number" + }, + "used_percent": { + "type": "number" + } + } + }, + "network_speed": { + "type": "object", + "keys": { + "interfaces": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "interface": { + "type": "string" + }, + "rx_bytes_per_sec": { + "type": "number" + }, + "total_rx_bytes": { + "type": "number" + }, + "total_tx_bytes": { + "type": "number" + }, + "tx_bytes_per_sec": { + "type": "number" + } + } + } + ] + }, + "interval_seconds": { + "type": "number" + } + } + }, + "system_info": { + "type": "object", + "keys": { + "full_info": { + "type": "string" + }, + "machine": { + "type": "string" + }, + "nodename": { + "type": "string" + }, + "release": { + "type": "string" + }, + "sysname": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "temperature": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + } + ] + }, + "uptime": { + "type": "object", + "keys": { + "idle_seconds": { + "type": "number" + }, + "uptime_formatted": { + "type": "string" + }, + "uptime_seconds": { + "type": "number" + } + } + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getStatsCpu": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "core_count": { + "type": "number" + }, + "cores": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "architecture": { + "type": "string" + }, + "bogomips": { + "type": "string" + }, + "features": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "implementer": { + "type": "string" + }, + "part": { + "type": "string" + }, + "processor": { + "type": "number" + }, + "revision": { + "type": "string" + }, + "variant": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "architecture": { + "type": "string" + }, + "bogomips": { + "type": "string" + }, + "features": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "implementer": { + "type": "string" + }, + "part": { + "type": "string" + }, + "processor": { + "type": "number" + }, + "revision": { + "type": "string" + }, + "variant": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "architecture": { + "type": "string" + }, + "bogomips": { + "type": "string" + }, + "features": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "implementer": { + "type": "string" + }, + "part": { + "type": "string" + }, + "processor": { + "type": "number" + }, + "revision": { + "type": "string" + }, + "variant": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "architecture": { + "type": "string" + }, + "bogomips": { + "type": "string" + }, + "features": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "implementer": { + "type": "string" + }, + "part": { + "type": "string" + }, + "processor": { + "type": "number" + }, + "revision": { + "type": "string" + }, + "variant": { + "type": "string" + } + } + } + ] + }, + "hardware": { + "type": "string" + }, + "model_name": { + "type": "string" + }, + "serial": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getVoicemailStatus": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-1::getWorkMode": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "mode": { + "type": "string" + }, + "worker_running": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getAirplaneMode": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "enabled": { + "type": "boolean" + }, + "online": { + "type": "boolean" + }, + "powered": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getApn": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "contexts": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "active": { + "type": "boolean" + }, + "apn": { + "type": "string" + }, + "auth_method": { + "type": "string" + }, + "context_type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "password": { + "type": "string" + }, + "path": { + "type": "string" + }, + "protocol": { + "type": "string" + }, + "username": { + "type": "string" + } + } + } + ] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getAuthSettings": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "configured": { + "type": "boolean" + }, + "settings": { + "type": "object", + "keys": { + "idle_timeout_seconds": { + "type": "number" + }, + "password_min_length": { + "type": "number" + }, + "password_protection_enabled": { + "type": "boolean" + }, + "password_require_digits": { + "type": "boolean" + }, + "password_require_letters": { + "type": "boolean" + }, + "password_require_symbols": { + "type": "boolean" + }, + "session_ttl_seconds": { + "type": "number" + } + } + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getAuthStatus": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "authenticated": { + "type": "boolean" + }, + "configured": { + "type": "boolean" + }, + "settings": { + "type": "object", + "keys": { + "idle_timeout_seconds": { + "type": "number" + }, + "password_min_length": { + "type": "number" + }, + "password_protection_enabled": { + "type": "boolean" + }, + "password_require_digits": { + "type": "boolean" + }, + "password_require_letters": { + "type": "boolean" + }, + "password_require_symbols": { + "type": "boolean" + }, + "session_ttl_seconds": { + "type": "number" + } + } + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getAutomationConfig": { + "type": "object", + "keys": { + "text": { + "type": "string" + } + } + }, + "instance-2::getBandLock": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "locked": { + "type": "boolean" + }, + "lte_fdd_bands": { + "type": "array", + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "lte_tdd_bands": { + "type": "array", + "items": [] + }, + "nr_fdd_bands": { + "type": "array", + "items": [] + }, + "nr_tdd_bands": { + "type": "array", + "items": [] + }, + "supported_lte_fdd_bands": { + "type": "array", + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "supported_lte_tdd_bands": { + "type": "array", + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "supported_nr_fdd_bands": { + "type": "array", + "items": [] + }, + "supported_nr_tdd_bands": { + "type": "array", + "items": [] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getBasebandRestartStatus": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "running": { + "type": "boolean" + }, + "steps": { + "type": "array", + "items": [] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getCallForwarding": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getCallSettings": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "called_line_presentation": { + "type": "string" + }, + "calling_line_presentation": { + "type": "string" + }, + "calling_line_restriction": { + "type": "string" + }, + "calling_name_presentation": { + "type": "string" + }, + "connected_line_presentation": { + "type": "string" + }, + "connected_line_restriction": { + "type": "string" + }, + "hide_caller_id": { + "type": "string" + }, + "voice_call_waiting": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getCallVolume": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getCalls": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "calls": { + "type": "array", + "items": [] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getCellLock": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "any_locked": { + "type": "boolean" + }, + "rat_status": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "arfcn": { + "type": "null" + }, + "enabled": { + "type": "boolean" + }, + "lock_type": { + "type": "number" + }, + "pci": { + "type": "null" + }, + "rat": { + "type": "number" + }, + "rat_name": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "arfcn": { + "type": "null" + }, + "enabled": { + "type": "boolean" + }, + "lock_type": { + "type": "number" + }, + "pci": { + "type": "null" + }, + "rat": { + "type": "number" + }, + "rat_name": { + "type": "string" + } + } + } + ] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getCells": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "cells": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "arfcn": { + "type": "string" + }, + "band": { + "type": "string" + }, + "cell_id": { + "type": "number" + }, + "earfcn": { + "type": "string" + }, + "is_serving": { + "type": "boolean" + }, + "pci": { + "type": "string" + }, + "rsrp": { + "type": "string" + }, + "rsrq": { + "type": "string" + }, + "sinr": { + "type": "string" + }, + "tech": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + ] + }, + "serving_cell": { + "type": "object", + "keys": { + "cell_id": { + "type": "number" + }, + "tac": { + "type": "number" + }, + "tech": { + "type": "string" + } + } + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getData": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "active": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getDevice": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "imei": { + "type": "string" + }, + "manufacturer": { + "type": "string" + }, + "model": { + "type": "string" + }, + "online": { + "type": "boolean" + }, + "powered": { + "type": "boolean" + }, + "revision": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getDeviceNetworkDdnsConfig": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "access_id": { + "type": "string" + }, + "access_secret": { + "type": "string" + }, + "access_secret_set": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "interval_seconds": { + "type": "number" + }, + "ipv4": { + "type": "object", + "keys": { + "domains": { + "type": "array", + "items": [] + }, + "enabled": { + "type": "boolean" + }, + "get_type": { + "type": "string" + }, + "interface_name": { + "type": "string" + }, + "urls": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + } + } + }, + "ipv6": { + "type": "object", + "keys": { + "domains": { + "type": "array", + "items": [] + }, + "enabled": { + "type": "boolean" + }, + "get_type": { + "type": "string" + }, + "interface_name": { + "type": "string" + }, + "urls": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + } + } + }, + "provider": { + "type": "string" + }, + "ttl": { + "type": "number" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getDeviceNetworkDdnsStatus": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "enabled": { + "type": "boolean" + }, + "last_ipv4": { + "type": "null" + }, + "last_ipv6": { + "type": "null" + }, + "last_message": { + "type": "null" + }, + "last_sync_at": { + "type": "null" + }, + "provider": { + "type": "string" + }, + "running": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getDeviceNetworkWlanProfiles": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "profiles": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "active": { + "type": "boolean" + }, + "auto_join": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "interface_name": { + "type": "string" + }, + "ssid": { + "type": "string" + }, + "uuid": { + "type": "string" + } + } + } + ] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getDeviceNetworkWlanStatus": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "available": { + "type": "boolean" + }, + "connected": { + "type": "boolean" + }, + "connection_id": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "hardware_enabled": { + "type": "boolean" + }, + "interface_name": { + "type": "string" + }, + "ipv4_addresses": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + }, + "ipv4_gateway": { + "type": "string" + }, + "ipv6_addresses": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "ssid": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getEsimConfig": { + "type": "object", + "keys": { + "text": { + "type": "string" + } + } + }, + "instance-2::getEsimLpacStatus": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getHealth": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "platform": { + "type": "string" + }, + "status": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "instance-2::getImsStatus": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getLocationCellInfo": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "available": { + "type": "boolean" + }, + "cell_info": { + "type": "object", + "keys": { + "arfcn": { + "type": "number" + }, + "cid": { + "type": "number" + }, + "lac": { + "type": "number" + }, + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + }, + "pci": { + "type": "number" + }, + "radio_type": { + "type": "string" + }, + "rsrq": { + "type": "number" + }, + "signal_strength": { + "type": "number" + } + } + }, + "cells": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "arfcn": { + "type": "number" + }, + "cid": { + "type": "number" + }, + "lac": { + "type": "number" + }, + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + }, + "pci": { + "type": "number" + }, + "radio_type": { + "type": "string" + }, + "rsrq": { + "type": "number" + }, + "signal_strength": { + "type": "number" + } + } + } + ] + }, + "neighbor_cells": { + "type": "array", + "items": [] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getNetwork": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + }, + "operator_name": { + "type": "string" + }, + "registration_status": { + "type": "string" + }, + "signal_strength": { + "type": "number" + }, + "technology_preference": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getNetworkConnectionAddresses": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "ipv4": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + }, + "ipv4_interface": { + "type": "string" + }, + "ipv6": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "ipv6_interface": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getNetworkInterfaces": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "interfaces": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + } + ] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mac_address": { + "type": "string" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mac_address": { + "type": "string" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mac_address": { + "type": "string" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "address": { + "type": "string" + }, + "ip_type": { + "type": "string" + }, + "prefix_len": { + "type": "number" + }, + "scope": { + "type": "string" + } + } + } + ] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mac_address": { + "type": "string" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "ip_addresses": { + "type": "array", + "items": [] + }, + "is_cellular": { + "type": "boolean" + }, + "is_default_ipv4": { + "type": "boolean" + }, + "is_default_ipv6": { + "type": "boolean" + }, + "is_wireless": { + "type": "boolean" + }, + "mtu": { + "type": "number" + }, + "name": { + "type": "string" + }, + "rx_bytes": { + "type": "number" + }, + "rx_errors": { + "type": "number" + }, + "rx_packets": { + "type": "number" + }, + "status": { + "type": "string" + }, + "tx_bytes": { + "type": "number" + }, + "tx_errors": { + "type": "number" + }, + "tx_packets": { + "type": "number" + } + } + } + ] + }, + "total_count": { + "type": "number" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getNetworkOperators": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "operators": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + }, + "name": { + "type": "string" + }, + "path": { + "type": "string" + }, + "status": { + "type": "string" + }, + "technologies": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + } + } + } + ] + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getNetworkSignalStrength": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "strength": { + "type": "number" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getNotificationsConfig": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "channels": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "config": { + "type": "object", + "keys": { + "headers": { + "type": "object", + "keys": {} + }, + "secret": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "config": { + "type": "object", + "keys": { + "auto_copy": { + "type": "boolean" + }, + "device_key": { + "type": "string" + }, + "group": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "level": { + "type": "string" + }, + "save_history": { + "type": "boolean" + }, + "server_url": { + "type": "string" + }, + "sound": { + "type": "string" + }, + "title_template": { + "type": "string" + } + } + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + ] + }, + "log_cleanup": { + "type": "object", + "keys": { + "max_entries": { + "type": "number" + }, + "max_entries_enabled": { + "type": "boolean" + }, + "retention_days": { + "type": "number" + }, + "retention_days_enabled": { + "type": "boolean" + } + } + }, + "rules": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "channel_ids": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + }, + "ddns_failure_threshold": { + "type": "number" + }, + "enabled": { + "type": "boolean" + }, + "event_codes": { + "type": "array", + "items": [] + }, + "id": { + "type": "string" + }, + "matcher": { + "type": "object", + "keys": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "name": { + "type": "string" + }, + "quiet_hours": { + "type": "array", + "items": [] + }, + "template": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "channel_ids": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + }, + "ddns_failure_threshold": { + "type": "number" + }, + "enabled": { + "type": "boolean" + }, + "event_codes": { + "type": "array", + "items": [] + }, + "id": { + "type": "string" + }, + "matcher": { + "type": "object", + "keys": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "name": { + "type": "string" + }, + "quiet_hours": { + "type": "array", + "items": [] + }, + "template": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + ] + }, + "version": { + "type": "number" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getOtaStatus": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "current_commit": { + "type": "string" + }, + "current_version": { + "type": "string" + }, + "pending_update": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getRadioMode": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "mode": { + "type": "string" + }, + "supported_modes": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "technology_preference": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getRoaming": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "is_roaming": { + "type": "boolean" + }, + "roaming_allowed": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getSim": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "iccid": { + "type": "string" + }, + "imsi": { + "type": "string" + }, + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + }, + "phone_number_is_manual": { + "type": "boolean" + }, + "phone_numbers": { + "type": "array", + "items": [ + { + "type": "string" + } + ] + }, + "present": { + "type": "boolean" + }, + "sms_center": { + "type": "string" + }, + "sms_center_is_manual": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getSmsStats": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "incoming": { + "type": "number" + }, + "outgoing": { + "type": "number" + }, + "push_attempted": { + "type": "number" + }, + "pushed": { + "type": "number" + }, + "total": { + "type": "number" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getStats": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "cpu_load": { + "type": "object", + "keys": { + "core_count": { + "type": "number" + }, + "load_15min": { + "type": "number" + }, + "load_1min": { + "type": "number" + }, + "load_5min": { + "type": "number" + }, + "load_percent": { + "type": "number" + } + } + }, + "disk": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "available_bytes": { + "type": "number" + }, + "fs_type": { + "type": "string" + }, + "mount_point": { + "type": "string" + }, + "total_bytes": { + "type": "number" + }, + "used_bytes": { + "type": "number" + }, + "used_percent": { + "type": "number" + } + } + }, + { + "type": "object", + "keys": { + "available_bytes": { + "type": "number" + }, + "fs_type": { + "type": "string" + }, + "mount_point": { + "type": "string" + }, + "total_bytes": { + "type": "number" + }, + "used_bytes": { + "type": "number" + }, + "used_percent": { + "type": "number" + } + } + } + ] + }, + "memory": { + "type": "object", + "keys": { + "available_bytes": { + "type": "number" + }, + "buffers_bytes": { + "type": "number" + }, + "cached_bytes": { + "type": "number" + }, + "total_bytes": { + "type": "number" + }, + "used_bytes": { + "type": "number" + }, + "used_percent": { + "type": "number" + } + } + }, + "network_speed": { + "type": "object", + "keys": { + "interfaces": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "interface": { + "type": "string" + }, + "rx_bytes_per_sec": { + "type": "number" + }, + "total_rx_bytes": { + "type": "number" + }, + "total_tx_bytes": { + "type": "number" + }, + "tx_bytes_per_sec": { + "type": "number" + } + } + } + ] + }, + "interval_seconds": { + "type": "number" + } + } + }, + "system_info": { + "type": "object", + "keys": { + "full_info": { + "type": "string" + }, + "machine": { + "type": "string" + }, + "nodename": { + "type": "string" + }, + "release": { + "type": "string" + }, + "sysname": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "temperature": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "temperature": { + "type": "number" + }, + "type": { + "type": "string" + }, + "zone": { + "type": "string" + } + } + } + ] + }, + "uptime": { + "type": "object", + "keys": { + "idle_seconds": { + "type": "number" + }, + "uptime_formatted": { + "type": "string" + }, + "uptime_seconds": { + "type": "number" + } + } + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getStatsCpu": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "core_count": { + "type": "number" + }, + "cores": { + "type": "array", + "items": [ + { + "type": "object", + "keys": { + "architecture": { + "type": "string" + }, + "bogomips": { + "type": "string" + }, + "features": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "implementer": { + "type": "string" + }, + "part": { + "type": "string" + }, + "processor": { + "type": "number" + }, + "revision": { + "type": "string" + }, + "variant": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "architecture": { + "type": "string" + }, + "bogomips": { + "type": "string" + }, + "features": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "implementer": { + "type": "string" + }, + "part": { + "type": "string" + }, + "processor": { + "type": "number" + }, + "revision": { + "type": "string" + }, + "variant": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "architecture": { + "type": "string" + }, + "bogomips": { + "type": "string" + }, + "features": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "implementer": { + "type": "string" + }, + "part": { + "type": "string" + }, + "processor": { + "type": "number" + }, + "revision": { + "type": "string" + }, + "variant": { + "type": "string" + } + } + }, + { + "type": "object", + "keys": { + "architecture": { + "type": "string" + }, + "bogomips": { + "type": "string" + }, + "features": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "implementer": { + "type": "string" + }, + "part": { + "type": "string" + }, + "processor": { + "type": "number" + }, + "revision": { + "type": "string" + }, + "variant": { + "type": "string" + } + } + } + ] + }, + "hardware": { + "type": "string" + }, + "model_name": { + "type": "string" + }, + "serial": { + "type": "string" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getVoicemailStatus": { + "type": "object", + "keys": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "instance-2::getWorkMode": { + "type": "object", + "keys": { + "data": { + "type": "object", + "keys": { + "mode": { + "type": "string" + }, + "worker_running": { + "type": "boolean" + } + } + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + } + } +} diff --git a/packages/test-fixtures/src/simadmin/automation/instance-1--getAutomationConfig.json b/packages/test-fixtures/src/simadmin/automation/instance-1--getAutomationConfig.json new file mode 100644 index 0000000..c466a45 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/automation/instance-1--getAutomationConfig.json @@ -0,0 +1,17 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getAutomationConfig", + "method": "GET", + "pathTemplate": "/api/automation/config", + "redacted": true, + "statusCategory": "unsupported", + "httpStatus": 404, + "contentType": "text/plain", + "latencyBucket": "<250ms", + "payload": { + "text": "[REDACTED]" + } +} diff --git a/packages/test-fixtures/src/simadmin/automation/instance-2--getAutomationConfig.json b/packages/test-fixtures/src/simadmin/automation/instance-2--getAutomationConfig.json new file mode 100644 index 0000000..7b0ed0f --- /dev/null +++ b/packages/test-fixtures/src/simadmin/automation/instance-2--getAutomationConfig.json @@ -0,0 +1,17 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getAutomationConfig", + "method": "GET", + "pathTemplate": "/api/automation/config", + "redacted": true, + "statusCategory": "unsupported", + "httpStatus": 404, + "contentType": "text/plain", + "latencyBucket": "<250ms", + "payload": { + "text": "[REDACTED]" + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-1--getCallForwarding.json b/packages/test-fixtures/src/simadmin/calls/instance-1--getCallForwarding.json new file mode 100644 index 0000000..024f185 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-1--getCallForwarding.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getCallForwarding", + "method": "GET", + "pathTemplate": "/api/call/forwarding", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "error", + "message": "Call forwarding is not exposed by ModemManager on this backend" + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-1--getCallSettings.json b/packages/test-fixtures/src/simadmin/calls/instance-1--getCallSettings.json new file mode 100644 index 0000000..2aa0cdf --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-1--getCallSettings.json @@ -0,0 +1,28 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getCallSettings", + "method": "GET", + "pathTemplate": "/api/call/settings", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "calling_line_presentation": "unknown", + "calling_name_presentation": "unknown", + "connected_line_presentation": "unknown", + "connected_line_restriction": "unknown", + "called_line_presentation": "unknown", + "calling_line_restriction": "unknown", + "hide_caller_id": "unknown", + "voice_call_waiting": "unknown" + } + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-1--getCallVolume.json b/packages/test-fixtures/src/simadmin/calls/instance-1--getCallVolume.json new file mode 100644 index 0000000..e1aa257 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-1--getCallVolume.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getCallVolume", + "method": "GET", + "pathTemplate": "/api/call/volume", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "error", + "message": "Call volume control is not exposed by ModemManager on this backend" + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-1--getCalls.json b/packages/test-fixtures/src/simadmin/calls/instance-1--getCalls.json new file mode 100644 index 0000000..5076797 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-1--getCalls.json @@ -0,0 +1,21 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getCalls", + "method": "GET", + "pathTemplate": "/api/calls", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": ">3s", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "calls": [] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-1--getImsStatus.json b/packages/test-fixtures/src/simadmin/calls/instance-1--getImsStatus.json new file mode 100644 index 0000000..38b7200 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-1--getImsStatus.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getImsStatus", + "method": "GET", + "pathTemplate": "/api/ims/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "error", + "message": "IMS status is not exposed by ModemManager on this backend" + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-1--getVoicemailStatus.json b/packages/test-fixtures/src/simadmin/calls/instance-1--getVoicemailStatus.json new file mode 100644 index 0000000..10eff7e --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-1--getVoicemailStatus.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getVoicemailStatus", + "method": "GET", + "pathTemplate": "/api/voicemail/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "error", + "message": "Voicemail status is not exposed by ModemManager on this backend" + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-2--getCallForwarding.json b/packages/test-fixtures/src/simadmin/calls/instance-2--getCallForwarding.json new file mode 100644 index 0000000..3a38603 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-2--getCallForwarding.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getCallForwarding", + "method": "GET", + "pathTemplate": "/api/call/forwarding", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "error", + "message": "Call forwarding is not exposed by ModemManager on this backend" + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-2--getCallSettings.json b/packages/test-fixtures/src/simadmin/calls/instance-2--getCallSettings.json new file mode 100644 index 0000000..0c8b4c9 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-2--getCallSettings.json @@ -0,0 +1,28 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getCallSettings", + "method": "GET", + "pathTemplate": "/api/call/settings", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "calling_line_presentation": "unknown", + "calling_name_presentation": "unknown", + "connected_line_presentation": "unknown", + "connected_line_restriction": "unknown", + "called_line_presentation": "unknown", + "calling_line_restriction": "unknown", + "hide_caller_id": "unknown", + "voice_call_waiting": "unknown" + } + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-2--getCallVolume.json b/packages/test-fixtures/src/simadmin/calls/instance-2--getCallVolume.json new file mode 100644 index 0000000..dadd48f --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-2--getCallVolume.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getCallVolume", + "method": "GET", + "pathTemplate": "/api/call/volume", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "error", + "message": "Call volume control is not exposed by ModemManager on this backend" + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-2--getCalls.json b/packages/test-fixtures/src/simadmin/calls/instance-2--getCalls.json new file mode 100644 index 0000000..2f6422e --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-2--getCalls.json @@ -0,0 +1,21 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getCalls", + "method": "GET", + "pathTemplate": "/api/calls", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": ">3s", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "calls": [] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-2--getImsStatus.json b/packages/test-fixtures/src/simadmin/calls/instance-2--getImsStatus.json new file mode 100644 index 0000000..2159fc9 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-2--getImsStatus.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getImsStatus", + "method": "GET", + "pathTemplate": "/api/ims/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "error", + "message": "IMS status is not exposed by ModemManager on this backend" + } +} diff --git a/packages/test-fixtures/src/simadmin/calls/instance-2--getVoicemailStatus.json b/packages/test-fixtures/src/simadmin/calls/instance-2--getVoicemailStatus.json new file mode 100644 index 0000000..64c23d2 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/calls/instance-2--getVoicemailStatus.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getVoicemailStatus", + "method": "GET", + "pathTemplate": "/api/voicemail/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "error", + "message": "Voicemail status is not exposed by ModemManager on this backend" + } +} diff --git a/packages/test-fixtures/src/simadmin/cellular/instance-1--getCells.json b/packages/test-fixtures/src/simadmin/cellular/instance-1--getCells.json new file mode 100644 index 0000000..ec97938 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/cellular/instance-1--getCells.json @@ -0,0 +1,40 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getCells", + "method": "GET", + "pathTemplate": "/api/cells", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "serving_cell": { + "tech": "lte", + "cell_id": 0, + "tac": 0 + }, + "cells": [ + { + "is_serving": true, + "tech": "lte", + "cell_id": 0, + "band": "B3", + "arfcn": "1400", + "pci": "[REDACTED]", + "rsrp": "-8760", + "rsrq": "-870", + "sinr": "", + "earfcn": "1400", + "type": "LTE" + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/cellular/instance-1--getLocationCellInfo.json b/packages/test-fixtures/src/simadmin/cellular/instance-1--getLocationCellInfo.json new file mode 100644 index 0000000..e685b54 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/cellular/instance-1--getLocationCellInfo.json @@ -0,0 +1,46 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getLocationCellInfo", + "method": "GET", + "pathTemplate": "/api/location/cell-info", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "available": true, + "cell_info": { + "mcc": "460", + "mnc": "00", + "lac": 0, + "cid": 0, + "signal_strength": -88, + "radio_type": "LTE", + "arfcn": 1400, + "pci": 0, + "rsrq": -8.7 + }, + "neighbor_cells": [], + "cells": [ + { + "mcc": "460", + "mnc": "00", + "lac": 0, + "cid": 0, + "signal_strength": -88, + "radio_type": "LTE", + "arfcn": 1400, + "pci": 0, + "rsrq": -8.7 + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/cellular/instance-1--getNetwork.json b/packages/test-fixtures/src/simadmin/cellular/instance-1--getNetwork.json new file mode 100644 index 0000000..8cdf9dc --- /dev/null +++ b/packages/test-fixtures/src/simadmin/cellular/instance-1--getNetwork.json @@ -0,0 +1,26 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getNetwork", + "method": "GET", + "pathTemplate": "/api/network", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "operator_name": "中国移动", + "registration_status": "registered", + "technology_preference": "lte-advanced", + "signal_strength": 80, + "mcc": "460", + "mnc": "00" + } + } +} diff --git a/packages/test-fixtures/src/simadmin/cellular/instance-1--getNetworkOperators.json b/packages/test-fixtures/src/simadmin/cellular/instance-1--getNetworkOperators.json new file mode 100644 index 0000000..85b7ac9 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/cellular/instance-1--getNetworkOperators.json @@ -0,0 +1,32 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getNetworkOperators", + "method": "GET", + "pathTemplate": "/api/network/operators", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "operators": [ + { + "path": "[REDACTED]", + "name": "中国移动", + "status": "current", + "mcc": "460", + "mnc": "00", + "technologies": [ + "LTE-ADVANCED" + ] + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/cellular/instance-1--getNetworkSignalStrength.json b/packages/test-fixtures/src/simadmin/cellular/instance-1--getNetworkSignalStrength.json new file mode 100644 index 0000000..5a00ea5 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/cellular/instance-1--getNetworkSignalStrength.json @@ -0,0 +1,21 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getNetworkSignalStrength", + "method": "GET", + "pathTemplate": "/api/network/signal-strength", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "strength": 80 + } + } +} diff --git a/packages/test-fixtures/src/simadmin/cellular/instance-2--getCells.json b/packages/test-fixtures/src/simadmin/cellular/instance-2--getCells.json new file mode 100644 index 0000000..a4172c1 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/cellular/instance-2--getCells.json @@ -0,0 +1,40 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getCells", + "method": "GET", + "pathTemplate": "/api/cells", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "serving_cell": { + "tech": "lte", + "cell_id": 0, + "tac": 0 + }, + "cells": [ + { + "is_serving": true, + "tech": "lte", + "cell_id": 0, + "band": "B3", + "arfcn": "1400", + "pci": "[REDACTED]", + "rsrp": "-9010", + "rsrq": "-900", + "sinr": "", + "earfcn": "1400", + "type": "LTE" + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/cellular/instance-2--getLocationCellInfo.json b/packages/test-fixtures/src/simadmin/cellular/instance-2--getLocationCellInfo.json new file mode 100644 index 0000000..bb04c38 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/cellular/instance-2--getLocationCellInfo.json @@ -0,0 +1,46 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getLocationCellInfo", + "method": "GET", + "pathTemplate": "/api/location/cell-info", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "available": true, + "cell_info": { + "mcc": "460", + "mnc": "00", + "lac": 0, + "cid": 0, + "signal_strength": -90, + "radio_type": "LTE", + "arfcn": 1400, + "pci": 0, + "rsrq": -8.9 + }, + "neighbor_cells": [], + "cells": [ + { + "mcc": "460", + "mnc": "00", + "lac": 0, + "cid": 0, + "signal_strength": -90, + "radio_type": "LTE", + "arfcn": 1400, + "pci": 0, + "rsrq": -8.9 + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/cellular/instance-2--getNetwork.json b/packages/test-fixtures/src/simadmin/cellular/instance-2--getNetwork.json new file mode 100644 index 0000000..207e383 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/cellular/instance-2--getNetwork.json @@ -0,0 +1,26 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getNetwork", + "method": "GET", + "pathTemplate": "/api/network", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "operator_name": "中国移动", + "registration_status": "registered", + "technology_preference": "lte-advanced", + "signal_strength": 76, + "mcc": "460", + "mnc": "00" + } + } +} diff --git a/packages/test-fixtures/src/simadmin/cellular/instance-2--getNetworkOperators.json b/packages/test-fixtures/src/simadmin/cellular/instance-2--getNetworkOperators.json new file mode 100644 index 0000000..083c46b --- /dev/null +++ b/packages/test-fixtures/src/simadmin/cellular/instance-2--getNetworkOperators.json @@ -0,0 +1,32 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getNetworkOperators", + "method": "GET", + "pathTemplate": "/api/network/operators", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "operators": [ + { + "path": "[REDACTED]", + "name": "中国移动", + "status": "current", + "mcc": "460", + "mnc": "00", + "technologies": [ + "LTE-ADVANCED" + ] + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/cellular/instance-2--getNetworkSignalStrength.json b/packages/test-fixtures/src/simadmin/cellular/instance-2--getNetworkSignalStrength.json new file mode 100644 index 0000000..6c83745 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/cellular/instance-2--getNetworkSignalStrength.json @@ -0,0 +1,21 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getNetworkSignalStrength", + "method": "GET", + "pathTemplate": "/api/network/signal-strength", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "strength": 76 + } + } +} diff --git a/packages/test-fixtures/src/simadmin/data-connection/instance-1--getAirplaneMode.json b/packages/test-fixtures/src/simadmin/data-connection/instance-1--getAirplaneMode.json new file mode 100644 index 0000000..2c991eb --- /dev/null +++ b/packages/test-fixtures/src/simadmin/data-connection/instance-1--getAirplaneMode.json @@ -0,0 +1,23 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getAirplaneMode", + "method": "GET", + "pathTemplate": "/api/airplane-mode", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "enabled": false, + "powered": true, + "online": true + } + } +} diff --git a/packages/test-fixtures/src/simadmin/data-connection/instance-1--getApn.json b/packages/test-fixtures/src/simadmin/data-connection/instance-1--getApn.json new file mode 100644 index 0000000..84499b2 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/data-connection/instance-1--getApn.json @@ -0,0 +1,33 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getApn", + "method": "GET", + "pathTemplate": "/api/apn", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "contexts": [ + { + "path": "[REDACTED]", + "name": "default", + "active": false, + "apn": "cmnet", + "protocol": "dual", + "username": "[REDACTED]", + "password": "[REDACTED]", + "auth_method": "chap", + "context_type": "internet" + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/data-connection/instance-1--getBasebandRestartStatus.json b/packages/test-fixtures/src/simadmin/data-connection/instance-1--getBasebandRestartStatus.json new file mode 100644 index 0000000..f8426af --- /dev/null +++ b/packages/test-fixtures/src/simadmin/data-connection/instance-1--getBasebandRestartStatus.json @@ -0,0 +1,22 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getBasebandRestartStatus", + "method": "GET", + "pathTemplate": "/api/baseband/restart/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "steps": [], + "running": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/data-connection/instance-1--getData.json b/packages/test-fixtures/src/simadmin/data-connection/instance-1--getData.json new file mode 100644 index 0000000..845a39a --- /dev/null +++ b/packages/test-fixtures/src/simadmin/data-connection/instance-1--getData.json @@ -0,0 +1,21 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getData", + "method": "GET", + "pathTemplate": "/api/data", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "active": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/data-connection/instance-1--getRoaming.json b/packages/test-fixtures/src/simadmin/data-connection/instance-1--getRoaming.json new file mode 100644 index 0000000..edcc73a --- /dev/null +++ b/packages/test-fixtures/src/simadmin/data-connection/instance-1--getRoaming.json @@ -0,0 +1,22 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getRoaming", + "method": "GET", + "pathTemplate": "/api/roaming", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "roaming_allowed": false, + "is_roaming": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/data-connection/instance-2--getAirplaneMode.json b/packages/test-fixtures/src/simadmin/data-connection/instance-2--getAirplaneMode.json new file mode 100644 index 0000000..8470ee2 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/data-connection/instance-2--getAirplaneMode.json @@ -0,0 +1,23 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getAirplaneMode", + "method": "GET", + "pathTemplate": "/api/airplane-mode", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "enabled": false, + "powered": true, + "online": true + } + } +} diff --git a/packages/test-fixtures/src/simadmin/data-connection/instance-2--getApn.json b/packages/test-fixtures/src/simadmin/data-connection/instance-2--getApn.json new file mode 100644 index 0000000..4b0a2fc --- /dev/null +++ b/packages/test-fixtures/src/simadmin/data-connection/instance-2--getApn.json @@ -0,0 +1,33 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getApn", + "method": "GET", + "pathTemplate": "/api/apn", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "contexts": [ + { + "path": "[REDACTED]", + "name": "default", + "active": false, + "apn": "cmnet", + "protocol": "dual", + "username": "[REDACTED]", + "password": "[REDACTED]", + "auth_method": "chap", + "context_type": "internet" + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/data-connection/instance-2--getBasebandRestartStatus.json b/packages/test-fixtures/src/simadmin/data-connection/instance-2--getBasebandRestartStatus.json new file mode 100644 index 0000000..67dc89b --- /dev/null +++ b/packages/test-fixtures/src/simadmin/data-connection/instance-2--getBasebandRestartStatus.json @@ -0,0 +1,22 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getBasebandRestartStatus", + "method": "GET", + "pathTemplate": "/api/baseband/restart/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "steps": [], + "running": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/data-connection/instance-2--getData.json b/packages/test-fixtures/src/simadmin/data-connection/instance-2--getData.json new file mode 100644 index 0000000..ec67102 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/data-connection/instance-2--getData.json @@ -0,0 +1,21 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getData", + "method": "GET", + "pathTemplate": "/api/data", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "active": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/data-connection/instance-2--getRoaming.json b/packages/test-fixtures/src/simadmin/data-connection/instance-2--getRoaming.json new file mode 100644 index 0000000..9c2fc38 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/data-connection/instance-2--getRoaming.json @@ -0,0 +1,22 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getRoaming", + "method": "GET", + "pathTemplate": "/api/roaming", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "roaming_allowed": false, + "is_roaming": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkDdnsConfig.json b/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkDdnsConfig.json new file mode 100644 index 0000000..004219e --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkDdnsConfig.json @@ -0,0 +1,53 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getDeviceNetworkDdnsConfig", + "method": "GET", + "pathTemplate": "/api/device-network/ddns/config", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "access_id": "[REDACTED]", + "access_secret": "[REDACTED]", + "access_secret_set": false, + "enabled": false, + "interval_seconds": 300, + "ipv4": { + "domains": [], + "enabled": true, + "get_type": "interface", + "interface_name": "", + "urls": [ + "[REDACTED]", + "[REDACTED]", + "[REDACTED]", + "[REDACTED]", + "[REDACTED]" + ] + }, + "ipv6": { + "domains": [], + "enabled": false, + "get_type": "interface", + "interface_name": "", + "urls": [ + "[REDACTED]", + "[REDACTED]", + "[REDACTED]", + "[REDACTED]", + "[REDACTED]" + ] + }, + "provider": "tencentcloud", + "ttl": 600 + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkDdnsStatus.json b/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkDdnsStatus.json new file mode 100644 index 0000000..53b5b3a --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkDdnsStatus.json @@ -0,0 +1,27 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getDeviceNetworkDdnsStatus", + "method": "GET", + "pathTemplate": "/api/device-network/ddns/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "enabled": false, + "running": false, + "provider": "tencentcloud", + "last_sync_at": null, + "last_ipv4": null, + "last_ipv6": null, + "last_message": null + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkWlanProfiles.json b/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkWlanProfiles.json new file mode 100644 index 0000000..2a712b3 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkWlanProfiles.json @@ -0,0 +1,30 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getDeviceNetworkWlanProfiles", + "method": "GET", + "pathTemplate": "/api/device-network/wlan/profiles", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "250ms-1s", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "profiles": [ + { + "id": "xiaomi", + "uuid": "[REDACTED]", + "ssid": "[REDACTED]", + "interface_name": "wlan0", + "active": true, + "auto_join": true + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkWlanStatus.json b/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkWlanStatus.json new file mode 100644 index 0000000..6b72999 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-1--getDeviceNetworkWlanStatus.json @@ -0,0 +1,36 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getDeviceNetworkWlanStatus", + "method": "GET", + "pathTemplate": "/api/device-network/wlan/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "250ms-1s", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "available": true, + "enabled": true, + "hardware_enabled": true, + "interface_name": "wlan0", + "connected": true, + "ssid": "[REDACTED]", + "connection_id": "xiaomi", + "ipv4_addresses": [ + "[REDACTED]" + ], + "ipv4_gateway": "[REDACTED]", + "ipv6_addresses": [ + "[REDACTED]", + "[REDACTED]", + "[REDACTED]" + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-1--getNetworkConnectionAddresses.json b/packages/test-fixtures/src/simadmin/device-network/instance-1--getNetworkConnectionAddresses.json new file mode 100644 index 0000000..40ace2a --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-1--getNetworkConnectionAddresses.json @@ -0,0 +1,29 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getNetworkConnectionAddresses", + "method": "GET", + "pathTemplate": "/api/network/connection-addresses", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "ipv4": [ + "[REDACTED]" + ], + "ipv6": [ + "[REDACTED]", + "[REDACTED]" + ], + "ipv4_interface": "wlan0", + "ipv6_interface": "wlan0" + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-1--getNetworkInterfaces.json b/packages/test-fixtures/src/simadmin/device-network/instance-1--getNetworkInterfaces.json new file mode 100644 index 0000000..af29f3e --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-1--getNetworkInterfaces.json @@ -0,0 +1,273 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getNetworkInterfaces", + "method": "GET", + "pathTemplate": "/api/network/interfaces", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "interfaces": [ + { + "name": "lo", + "status": "up", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 65536, + "ip_addresses": [ + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + }, + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + } + ], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "pan0", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mac_address": "[REDACTED]", + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "usb0", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mac_address": "[REDACTED]", + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "usb1", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mac_address": "[REDACTED]", + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wlan0", + "status": "up", + "is_wireless": true, + "is_cellular": false, + "is_default_ipv4": true, + "is_default_ipv6": true, + "mac_address": "[REDACTED]", + "mtu": 1500, + "ip_addresses": [ + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + }, + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + }, + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + }, + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + } + ], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan0", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan1", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan2", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan3", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan4", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan5", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan6", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan7", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + } + ], + "total_count": 13 + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkDdnsConfig.json b/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkDdnsConfig.json new file mode 100644 index 0000000..d72cf86 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkDdnsConfig.json @@ -0,0 +1,53 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getDeviceNetworkDdnsConfig", + "method": "GET", + "pathTemplate": "/api/device-network/ddns/config", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "access_id": "[REDACTED]", + "access_secret": "[REDACTED]", + "access_secret_set": false, + "enabled": false, + "interval_seconds": 300, + "ipv4": { + "domains": [], + "enabled": true, + "get_type": "interface", + "interface_name": "", + "urls": [ + "[REDACTED]", + "[REDACTED]", + "[REDACTED]", + "[REDACTED]", + "[REDACTED]" + ] + }, + "ipv6": { + "domains": [], + "enabled": false, + "get_type": "interface", + "interface_name": "", + "urls": [ + "[REDACTED]", + "[REDACTED]", + "[REDACTED]", + "[REDACTED]", + "[REDACTED]" + ] + }, + "provider": "tencentcloud", + "ttl": 600 + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkDdnsStatus.json b/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkDdnsStatus.json new file mode 100644 index 0000000..dbe6533 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkDdnsStatus.json @@ -0,0 +1,27 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getDeviceNetworkDdnsStatus", + "method": "GET", + "pathTemplate": "/api/device-network/ddns/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "enabled": false, + "running": false, + "provider": "tencentcloud", + "last_sync_at": null, + "last_ipv4": null, + "last_ipv6": null, + "last_message": null + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkWlanProfiles.json b/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkWlanProfiles.json new file mode 100644 index 0000000..9248c96 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkWlanProfiles.json @@ -0,0 +1,30 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getDeviceNetworkWlanProfiles", + "method": "GET", + "pathTemplate": "/api/device-network/wlan/profiles", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "profiles": [ + { + "id": "xiaomi", + "uuid": "[REDACTED]", + "ssid": "[REDACTED]", + "interface_name": "wlan0", + "active": true, + "auto_join": true + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkWlanStatus.json b/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkWlanStatus.json new file mode 100644 index 0000000..c630fc6 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-2--getDeviceNetworkWlanStatus.json @@ -0,0 +1,36 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getDeviceNetworkWlanStatus", + "method": "GET", + "pathTemplate": "/api/device-network/wlan/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "250ms-1s", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "available": true, + "enabled": true, + "hardware_enabled": true, + "interface_name": "wlan0", + "connected": true, + "ssid": "[REDACTED]", + "connection_id": "xiaomi", + "ipv4_addresses": [ + "[REDACTED]" + ], + "ipv4_gateway": "[REDACTED]", + "ipv6_addresses": [ + "[REDACTED]", + "[REDACTED]", + "[REDACTED]" + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-2--getNetworkConnectionAddresses.json b/packages/test-fixtures/src/simadmin/device-network/instance-2--getNetworkConnectionAddresses.json new file mode 100644 index 0000000..175e17c --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-2--getNetworkConnectionAddresses.json @@ -0,0 +1,29 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getNetworkConnectionAddresses", + "method": "GET", + "pathTemplate": "/api/network/connection-addresses", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "ipv4": [ + "[REDACTED]" + ], + "ipv6": [ + "[REDACTED]", + "[REDACTED]" + ], + "ipv4_interface": "wlan0", + "ipv6_interface": "wlan0" + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-network/instance-2--getNetworkInterfaces.json b/packages/test-fixtures/src/simadmin/device-network/instance-2--getNetworkInterfaces.json new file mode 100644 index 0000000..780f1c2 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-network/instance-2--getNetworkInterfaces.json @@ -0,0 +1,273 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getNetworkInterfaces", + "method": "GET", + "pathTemplate": "/api/network/interfaces", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "interfaces": [ + { + "name": "lo", + "status": "up", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 65536, + "ip_addresses": [ + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + }, + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + } + ], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "pan0", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mac_address": "[REDACTED]", + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "usb0", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mac_address": "[REDACTED]", + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "usb1", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mac_address": "[REDACTED]", + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wlan0", + "status": "up", + "is_wireless": true, + "is_cellular": false, + "is_default_ipv4": true, + "is_default_ipv6": true, + "mac_address": "[REDACTED]", + "mtu": 1500, + "ip_addresses": [ + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + }, + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + }, + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + }, + { + "address": "[REDACTED]", + "prefix_len": 0, + "ip_type": "[REDACTED]", + "scope": "[REDACTED]" + } + ], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan0", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan1", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan2", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan3", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan4", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan5", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan6", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + }, + { + "name": "wwan7", + "status": "down", + "is_wireless": false, + "is_cellular": false, + "is_default_ipv4": false, + "is_default_ipv6": false, + "mtu": 1500, + "ip_addresses": [], + "rx_bytes": 0, + "tx_bytes": 0, + "rx_packets": 0, + "tx_packets": 0, + "rx_errors": 0, + "tx_errors": 0 + } + ], + "total_count": 13 + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-system/instance-1--getDevice.json b/packages/test-fixtures/src/simadmin/device-system/instance-1--getDevice.json new file mode 100644 index 0000000..a1b674c --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-system/instance-1--getDevice.json @@ -0,0 +1,26 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getDevice", + "method": "GET", + "pathTemplate": "/api/device", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "250ms-1s", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "imei": "[REDACTED]", + "manufacturer": "QUALCOMM INCORPORATED", + "model": "0", + "revision": "[REDACTED]", + "online": true, + "powered": true + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-system/instance-1--getStats.json b/packages/test-fixtures/src/simadmin/device-system/instance-1--getStats.json new file mode 100644 index 0000000..566164d --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-system/instance-1--getStats.json @@ -0,0 +1,110 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getStats", + "method": "GET", + "pathTemplate": "/api/stats", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "1-3s", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "network_speed": { + "interfaces": [ + { + "interface": "wlan0", + "rx_bytes_per_sec": 2325, + "tx_bytes_per_sec": 86, + "total_rx_bytes": 0, + "total_tx_bytes": 0 + } + ], + "interval_seconds": 1 + }, + "memory": { + "total_bytes": 0, + "available_bytes": 0, + "used_bytes": 0, + "used_percent": 0, + "cached_bytes": 0, + "buffers_bytes": 36802560 + }, + "disk": [ + { + "mount_point": "/", + "fs_type": "ext4", + "total_bytes": 0, + "used_bytes": 0, + "available_bytes": 0, + "used_percent": 0 + }, + { + "mount_point": "/run", + "fs_type": "tmpfs", + "total_bytes": 38850560, + "used_bytes": 1277952, + "available_bytes": 37572608, + "used_percent": 0 + } + ], + "cpu_load": { + "load_1min": 0.06, + "load_5min": 0.05, + "load_15min": 0.01, + "core_count": 4, + "load_percent": 0 + }, + "uptime": { + "uptime_seconds": 0, + "idle_seconds": 0, + "uptime_formatted": "[REDACTED]" + }, + "system_info": { + "sysname": "Linux", + "nodename": "4G-wifi", + "release": "[REDACTED]", + "version": "[REDACTED]", + "machine": "[REDACTED]", + "full_info": "[REDACTED]" + }, + "temperature": [ + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + }, + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + }, + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + }, + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + }, + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + }, + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-system/instance-1--getStatsCpu.json b/packages/test-fixtures/src/simadmin/device-system/instance-1--getStatsCpu.json new file mode 100644 index 0000000..7dc5847 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-system/instance-1--getStatsCpu.json @@ -0,0 +1,90 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getStatsCpu", + "method": "GET", + "pathTemplate": "/api/stats/cpu", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "core_count": 4, + "cores": [ + { + "processor": 0, + "bogomips": "38.40", + "features": [ + "fp", + "asimd", + "evtstrm", + "crc32", + "cpuid" + ], + "implementer": "0x41", + "architecture": "8", + "variant": "0x0", + "part": "0xd03", + "revision": "[REDACTED]" + }, + { + "processor": 1, + "bogomips": "38.40", + "features": [ + "fp", + "asimd", + "evtstrm", + "crc32", + "cpuid" + ], + "implementer": "0x41", + "architecture": "8", + "variant": "0x0", + "part": "0xd03", + "revision": "[REDACTED]" + }, + { + "processor": 2, + "bogomips": "38.40", + "features": [ + "fp", + "asimd", + "evtstrm", + "crc32", + "cpuid" + ], + "implementer": "0x41", + "architecture": "8", + "variant": "0x0", + "part": "0xd03", + "revision": "[REDACTED]" + }, + { + "processor": 3, + "bogomips": "38.40", + "features": [ + "fp", + "asimd", + "evtstrm", + "crc32", + "cpuid" + ], + "implementer": "0x41", + "architecture": "8", + "variant": "0x0", + "part": "0xd03", + "revision": "[REDACTED]" + } + ], + "hardware": "", + "serial": "[REDACTED]", + "model_name": "ARM CPU (part: 0xd03)" + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-system/instance-2--getDevice.json b/packages/test-fixtures/src/simadmin/device-system/instance-2--getDevice.json new file mode 100644 index 0000000..955371f --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-system/instance-2--getDevice.json @@ -0,0 +1,26 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getDevice", + "method": "GET", + "pathTemplate": "/api/device", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "imei": "[REDACTED]", + "manufacturer": "QUALCOMM INCORPORATED", + "model": "0", + "revision": "[REDACTED]", + "online": true, + "powered": true + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-system/instance-2--getStats.json b/packages/test-fixtures/src/simadmin/device-system/instance-2--getStats.json new file mode 100644 index 0000000..24102e0 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-system/instance-2--getStats.json @@ -0,0 +1,110 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getStats", + "method": "GET", + "pathTemplate": "/api/stats", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "1-3s", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "network_speed": { + "interfaces": [ + { + "interface": "wlan0", + "rx_bytes_per_sec": 0, + "tx_bytes_per_sec": 86, + "total_rx_bytes": 0, + "total_tx_bytes": 0 + } + ], + "interval_seconds": 1 + }, + "memory": { + "total_bytes": 0, + "available_bytes": 0, + "used_bytes": 0, + "used_percent": 0, + "cached_bytes": 0, + "buffers_bytes": 37208064 + }, + "disk": [ + { + "mount_point": "/", + "fs_type": "ext4", + "total_bytes": 0, + "used_bytes": 0, + "available_bytes": 0, + "used_percent": 0 + }, + { + "mount_point": "/run", + "fs_type": "tmpfs", + "total_bytes": 38850560, + "used_bytes": 1277952, + "available_bytes": 37572608, + "used_percent": 0 + } + ], + "cpu_load": { + "load_1min": 0.08, + "load_5min": 0.03, + "load_15min": 0.01, + "core_count": 4, + "load_percent": 0 + }, + "uptime": { + "uptime_seconds": 0, + "idle_seconds": 0, + "uptime_formatted": "[REDACTED]" + }, + "system_info": { + "sysname": "Linux", + "nodename": "4G-wifi", + "release": "[REDACTED]", + "version": "[REDACTED]", + "machine": "[REDACTED]", + "full_info": "[REDACTED]" + }, + "temperature": [ + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + }, + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + }, + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + }, + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + }, + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + }, + { + "zone": "[REDACTED]", + "type": "[REDACTED]", + "temperature": 0 + } + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/device-system/instance-2--getStatsCpu.json b/packages/test-fixtures/src/simadmin/device-system/instance-2--getStatsCpu.json new file mode 100644 index 0000000..8a44479 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/device-system/instance-2--getStatsCpu.json @@ -0,0 +1,90 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getStatsCpu", + "method": "GET", + "pathTemplate": "/api/stats/cpu", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "core_count": 4, + "cores": [ + { + "processor": 0, + "bogomips": "38.40", + "features": [ + "fp", + "asimd", + "evtstrm", + "crc32", + "cpuid" + ], + "implementer": "0x41", + "architecture": "8", + "variant": "0x0", + "part": "0xd03", + "revision": "[REDACTED]" + }, + { + "processor": 1, + "bogomips": "38.40", + "features": [ + "fp", + "asimd", + "evtstrm", + "crc32", + "cpuid" + ], + "implementer": "0x41", + "architecture": "8", + "variant": "0x0", + "part": "0xd03", + "revision": "[REDACTED]" + }, + { + "processor": 2, + "bogomips": "38.40", + "features": [ + "fp", + "asimd", + "evtstrm", + "crc32", + "cpuid" + ], + "implementer": "0x41", + "architecture": "8", + "variant": "0x0", + "part": "0xd03", + "revision": "[REDACTED]" + }, + { + "processor": 3, + "bogomips": "38.40", + "features": [ + "fp", + "asimd", + "evtstrm", + "crc32", + "cpuid" + ], + "implementer": "0x41", + "architecture": "8", + "variant": "0x0", + "part": "0xd03", + "revision": "[REDACTED]" + } + ], + "hardware": "", + "serial": "[REDACTED]", + "model_name": "ARM CPU (part: 0xd03)" + } + } +} diff --git a/packages/test-fixtures/src/simadmin/instances-auth/instance-1--getAuthSettings.json b/packages/test-fixtures/src/simadmin/instances-auth/instance-1--getAuthSettings.json new file mode 100644 index 0000000..da4d224 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/instances-auth/instance-1--getAuthSettings.json @@ -0,0 +1,17 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getAuthSettings", + "method": "GET", + "pathTemplate": "/api/auth/settings", + "redacted": true, + "statusCategory": "unsupported", + "httpStatus": 404, + "contentType": "text/plain", + "latencyBucket": "<250ms", + "payload": { + "text": "[REDACTED]" + } +} diff --git a/packages/test-fixtures/src/simadmin/instances-auth/instance-1--getAuthStatus.json b/packages/test-fixtures/src/simadmin/instances-auth/instance-1--getAuthStatus.json new file mode 100644 index 0000000..daaee39 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/instances-auth/instance-1--getAuthStatus.json @@ -0,0 +1,17 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getAuthStatus", + "method": "GET", + "pathTemplate": "/api/auth/status", + "redacted": true, + "statusCategory": "unsupported", + "httpStatus": 404, + "contentType": "text/plain", + "latencyBucket": "<250ms", + "payload": { + "text": "[REDACTED]" + } +} diff --git a/packages/test-fixtures/src/simadmin/instances-auth/instance-1--getHealth.json b/packages/test-fixtures/src/simadmin/instances-auth/instance-1--getHealth.json new file mode 100644 index 0000000..a4295b1 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/instances-auth/instance-1--getHealth.json @@ -0,0 +1,20 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getHealth", + "method": "GET", + "pathTemplate": "/api/health", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "message": "Service is running", + "platform": "linux-modem", + "status": "ok", + "version": "1.0.6" + } +} diff --git a/packages/test-fixtures/src/simadmin/instances-auth/instance-2--getAuthSettings.json b/packages/test-fixtures/src/simadmin/instances-auth/instance-2--getAuthSettings.json new file mode 100644 index 0000000..8e9aafd --- /dev/null +++ b/packages/test-fixtures/src/simadmin/instances-auth/instance-2--getAuthSettings.json @@ -0,0 +1,30 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getAuthSettings", + "method": "GET", + "pathTemplate": "/api/auth/settings", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "configured": true, + "settings": { + "password_protection_enabled": false, + "password_min_length": 0, + "password_require_letters": false, + "password_require_digits": false, + "password_require_symbols": false, + "session_ttl_seconds": 604800, + "idle_timeout_seconds": 3600 + } + } + } +} diff --git a/packages/test-fixtures/src/simadmin/instances-auth/instance-2--getAuthStatus.json b/packages/test-fixtures/src/simadmin/instances-auth/instance-2--getAuthStatus.json new file mode 100644 index 0000000..cf25af3 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/instances-auth/instance-2--getAuthStatus.json @@ -0,0 +1,31 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getAuthStatus", + "method": "GET", + "pathTemplate": "/api/auth/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "configured": true, + "authenticated": true, + "settings": { + "password_protection_enabled": false, + "password_min_length": 0, + "password_require_letters": false, + "password_require_digits": false, + "password_require_symbols": false, + "session_ttl_seconds": 604800, + "idle_timeout_seconds": 3600 + } + } + } +} diff --git a/packages/test-fixtures/src/simadmin/instances-auth/instance-2--getHealth.json b/packages/test-fixtures/src/simadmin/instances-auth/instance-2--getHealth.json new file mode 100644 index 0000000..ec7f8e3 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/instances-auth/instance-2--getHealth.json @@ -0,0 +1,20 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getHealth", + "method": "GET", + "pathTemplate": "/api/health", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "message": "Service is running", + "platform": "linux-modem", + "status": "ok", + "version": "1.0.8" + } +} diff --git a/packages/test-fixtures/src/simadmin/messages/instance-1--getSmsStats.json b/packages/test-fixtures/src/simadmin/messages/instance-1--getSmsStats.json new file mode 100644 index 0000000..1d0bc86 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/messages/instance-1--getSmsStats.json @@ -0,0 +1,23 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getSmsStats", + "method": "GET", + "pathTemplate": "/api/sms/stats", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "total": 57, + "incoming": 57, + "outgoing": 0 + } + } +} diff --git a/packages/test-fixtures/src/simadmin/messages/instance-2--getSmsStats.json b/packages/test-fixtures/src/simadmin/messages/instance-2--getSmsStats.json new file mode 100644 index 0000000..8412d6b --- /dev/null +++ b/packages/test-fixtures/src/simadmin/messages/instance-2--getSmsStats.json @@ -0,0 +1,25 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getSmsStats", + "method": "GET", + "pathTemplate": "/api/sms/stats", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "total": 11, + "incoming": 11, + "outgoing": 0, + "pushed": 5, + "push_attempted": 5 + } + } +} diff --git a/packages/test-fixtures/src/simadmin/notifications/instance-1--getNotificationsConfig.json b/packages/test-fixtures/src/simadmin/notifications/instance-1--getNotificationsConfig.json new file mode 100644 index 0000000..39f4d90 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/notifications/instance-1--getNotificationsConfig.json @@ -0,0 +1,166 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getNotificationsConfig", + "method": "GET", + "pathTemplate": "/api/notifications/config", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "webhook": { + "enabled": false, + "url": "[REDACTED]", + "forward_sms": false, + "forward_calls": false, + "forward_ddns": false, + "forward_updates": false, + "headers": {}, + "secret": "[REDACTED]", + "sms_template": "[REDACTED]", + "call_template": "[REDACTED]", + "ddns_template": "[REDACTED]", + "update_template": "[REDACTED]" + }, + "bark": { + "enabled": true, + "forward_sms": true, + "forward_calls": true, + "forward_ddns": true, + "forward_updates": true, + "sms_template": "[REDACTED]", + "call_template": "[REDACTED]", + "ddns_template": "[REDACTED]", + "update_template": "[REDACTED]", + "server_url": "[REDACTED]", + "device_key": "[REDACTED]", + "title_template": "[REDACTED]", + "group": "", + "sound": "", + "level": "", + "icon": "", + "click_url": "[REDACTED]", + "copy": "", + "auto_copy": false, + "save_history": true + }, + "pushplus": { + "enabled": false, + "forward_sms": true, + "forward_calls": true, + "forward_ddns": true, + "forward_updates": true, + "sms_template": "[REDACTED]", + "call_template": "[REDACTED]", + "ddns_template": "[REDACTED]", + "update_template": "[REDACTED]", + "token": "[REDACTED]", + "title_template": "[REDACTED]", + "topic": "", + "template": "[REDACTED]", + "channel": "", + "option": "", + "callback_url": "[REDACTED]" + }, + "wecom_app": { + "enabled": false, + "forward_sms": true, + "forward_calls": true, + "forward_ddns": true, + "forward_updates": true, + "sms_template": "[REDACTED]", + "call_template": "[REDACTED]", + "ddns_template": "[REDACTED]", + "update_template": "[REDACTED]", + "corp_id": "", + "agent_id": "", + "secret": "[REDACTED]", + "to_user": "[REDACTED]", + "to_party": "", + "to_tag": "", + "safe": false + }, + "wecom_robot": { + "enabled": false, + "forward_sms": true, + "forward_calls": true, + "forward_ddns": true, + "forward_updates": true, + "sms_template": "[REDACTED]", + "call_template": "[REDACTED]", + "ddns_template": "[REDACTED]", + "update_template": "[REDACTED]", + "webhook_url": "[REDACTED]", + "key": "" + }, + "dingtalk_robot": { + "enabled": false, + "forward_sms": true, + "forward_calls": true, + "forward_ddns": true, + "forward_updates": true, + "sms_template": "[REDACTED]", + "call_template": "[REDACTED]", + "ddns_template": "[REDACTED]", + "update_template": "[REDACTED]", + "webhook_url": "[REDACTED]", + "access_token": "[REDACTED]", + "secret": "[REDACTED]", + "at_mobiles": "", + "at_all": false + }, + "dingtalk_app": { + "enabled": false, + "forward_sms": true, + "forward_calls": true, + "forward_ddns": true, + "forward_updates": true, + "sms_template": "[REDACTED]", + "call_template": "[REDACTED]", + "ddns_template": "[REDACTED]", + "update_template": "[REDACTED]", + "app_key": "", + "app_secret": "[REDACTED]", + "robot_code": "", + "open_conversation_id": "", + "msg_key": "sampleText" + }, + "feishu_robot": { + "enabled": false, + "forward_sms": true, + "forward_calls": true, + "forward_ddns": true, + "forward_updates": true, + "sms_template": "[REDACTED]", + "call_template": "[REDACTED]", + "ddns_template": "[REDACTED]", + "update_template": "[REDACTED]", + "webhook_url": "[REDACTED]", + "token": "[REDACTED]", + "secret": "[REDACTED]" + }, + "telegram": { + "enabled": false, + "forward_sms": true, + "forward_calls": true, + "forward_ddns": true, + "forward_updates": true, + "sms_template": "[REDACTED]", + "call_template": "[REDACTED]", + "ddns_template": "[REDACTED]", + "update_template": "[REDACTED]", + "bot_token": "[REDACTED]", + "chat_id": "", + "parse_mode": "", + "disable_web_page_preview": true + } + } + } +} diff --git a/packages/test-fixtures/src/simadmin/notifications/instance-2--getNotificationsConfig.json b/packages/test-fixtures/src/simadmin/notifications/instance-2--getNotificationsConfig.json new file mode 100644 index 0000000..c88a08f --- /dev/null +++ b/packages/test-fixtures/src/simadmin/notifications/instance-2--getNotificationsConfig.json @@ -0,0 +1,95 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getNotificationsConfig", + "method": "GET", + "pathTemplate": "/api/notifications/config", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "version": 2, + "channels": [ + { + "id": "[REDACTED]", + "type": "webhook", + "name": "Webhook", + "enabled": true, + "config": { + "headers": {}, + "secret": "[REDACTED]", + "url": "[REDACTED]" + } + }, + { + "id": "[REDACTED]", + "type": "bark", + "name": "Bark", + "enabled": true, + "config": { + "auto_copy": false, + "device_key": "[REDACTED]", + "group": "[REDACTED]", + "icon": "[REDACTED]", + "level": "[REDACTED]", + "save_history": false, + "server_url": "[REDACTED]", + "sound": "[REDACTED]", + "title_template": "[REDACTED]" + } + } + ], + "rules": [ + { + "id": "[REDACTED]", + "type": "sms", + "name": "aut", + "enabled": true, + "matcher": { + "field": "summary", + "operator": "always", + "value": "" + }, + "channel_ids": [ + "[REDACTED]" + ], + "event_codes": [], + "template": "[REDACTED]", + "quiet_hours": [], + "ddns_failure_threshold": 1 + }, + { + "id": "[REDACTED]", + "type": "sms", + "name": "默认短信规则", + "enabled": true, + "matcher": { + "field": "summary", + "operator": "always", + "value": "" + }, + "channel_ids": [ + "[REDACTED]" + ], + "event_codes": [], + "template": "[REDACTED]", + "quiet_hours": [], + "ddns_failure_threshold": 1 + } + ], + "log_cleanup": { + "retention_days_enabled": false, + "retention_days": 90, + "max_entries_enabled": false, + "max_entries": 10000 + } + } + } +} diff --git a/packages/test-fixtures/src/simadmin/ota/instance-1--getOtaStatus.json b/packages/test-fixtures/src/simadmin/ota/instance-1--getOtaStatus.json new file mode 100644 index 0000000..db75b57 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/ota/instance-1--getOtaStatus.json @@ -0,0 +1,23 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getOtaStatus", + "method": "GET", + "pathTemplate": "/api/ota/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "current_version": "1.0.6", + "current_commit": "738330d", + "pending_update": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/ota/instance-2--getOtaStatus.json b/packages/test-fixtures/src/simadmin/ota/instance-2--getOtaStatus.json new file mode 100644 index 0000000..a675b3d --- /dev/null +++ b/packages/test-fixtures/src/simadmin/ota/instance-2--getOtaStatus.json @@ -0,0 +1,23 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getOtaStatus", + "method": "GET", + "pathTemplate": "/api/ota/status", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "current_version": "1.0.8", + "current_commit": "70da241", + "pending_update": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/radio-lock/instance-1--getBandLock.json b/packages/test-fixtures/src/simadmin/radio-lock/instance-1--getBandLock.json new file mode 100644 index 0000000..997edc8 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/radio-lock/instance-1--getBandLock.json @@ -0,0 +1,44 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getBandLock", + "method": "GET", + "pathTemplate": "/api/band-lock", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "locked": true, + "supported_lte_fdd_bands": [ + 1, + 2, + 3, + 5, + 7, + 8, + 20 + ], + "supported_lte_tdd_bands": [ + 39, + 40 + ], + "supported_nr_fdd_bands": [], + "supported_nr_tdd_bands": [], + "lte_fdd_bands": [ + 1, + 3, + 5 + ], + "lte_tdd_bands": [], + "nr_fdd_bands": [], + "nr_tdd_bands": [] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/radio-lock/instance-1--getCellLock.json b/packages/test-fixtures/src/simadmin/radio-lock/instance-1--getCellLock.json new file mode 100644 index 0000000..8bcc5b6 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/radio-lock/instance-1--getCellLock.json @@ -0,0 +1,39 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getCellLock", + "method": "GET", + "pathTemplate": "/api/cell-lock", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "rat_status": [ + { + "rat": 12, + "rat_name": "LTE", + "enabled": false, + "lock_type": 0, + "pci": null, + "arfcn": null + }, + { + "rat": 16, + "rat_name": "NR", + "enabled": false, + "lock_type": 0, + "pci": null, + "arfcn": null + } + ], + "any_locked": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/radio-lock/instance-1--getRadioMode.json b/packages/test-fixtures/src/simadmin/radio-lock/instance-1--getRadioMode.json new file mode 100644 index 0000000..e5d57f4 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/radio-lock/instance-1--getRadioMode.json @@ -0,0 +1,26 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getRadioMode", + "method": "GET", + "pathTemplate": "/api/radio-mode", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "mode": "lte", + "technology_preference": "lte-advanced", + "supported_modes": [ + "auto", + "lte" + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/radio-lock/instance-2--getBandLock.json b/packages/test-fixtures/src/simadmin/radio-lock/instance-2--getBandLock.json new file mode 100644 index 0000000..dbcfa35 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/radio-lock/instance-2--getBandLock.json @@ -0,0 +1,44 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getBandLock", + "method": "GET", + "pathTemplate": "/api/band-lock", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "locked": true, + "supported_lte_fdd_bands": [ + 1, + 2, + 3, + 5, + 7, + 8, + 20 + ], + "supported_lte_tdd_bands": [ + 39, + 40 + ], + "supported_nr_fdd_bands": [], + "supported_nr_tdd_bands": [], + "lte_fdd_bands": [ + 1, + 3, + 5 + ], + "lte_tdd_bands": [], + "nr_fdd_bands": [], + "nr_tdd_bands": [] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/radio-lock/instance-2--getCellLock.json b/packages/test-fixtures/src/simadmin/radio-lock/instance-2--getCellLock.json new file mode 100644 index 0000000..5fb9e21 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/radio-lock/instance-2--getCellLock.json @@ -0,0 +1,39 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getCellLock", + "method": "GET", + "pathTemplate": "/api/cell-lock", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "rat_status": [ + { + "rat": 12, + "rat_name": "LTE", + "enabled": false, + "lock_type": 0, + "pci": null, + "arfcn": null + }, + { + "rat": 16, + "rat_name": "NR", + "enabled": false, + "lock_type": 0, + "pci": null, + "arfcn": null + } + ], + "any_locked": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/radio-lock/instance-2--getRadioMode.json b/packages/test-fixtures/src/simadmin/radio-lock/instance-2--getRadioMode.json new file mode 100644 index 0000000..a3bf4aa --- /dev/null +++ b/packages/test-fixtures/src/simadmin/radio-lock/instance-2--getRadioMode.json @@ -0,0 +1,26 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getRadioMode", + "method": "GET", + "pathTemplate": "/api/radio-mode", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "mode": "lte", + "technology_preference": "lte-advanced", + "supported_modes": [ + "auto", + "lte" + ] + } + } +} diff --git a/packages/test-fixtures/src/simadmin/sim/instance-1--getSim.json b/packages/test-fixtures/src/simadmin/sim/instance-1--getSim.json new file mode 100644 index 0000000..e6a8f8b --- /dev/null +++ b/packages/test-fixtures/src/simadmin/sim/instance-1--getSim.json @@ -0,0 +1,31 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getSim", + "method": "GET", + "pathTemplate": "/api/sim", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "250ms-1s", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "present": true, + "iccid": "[REDACTED]", + "imsi": "[REDACTED]", + "phone_numbers": [ + "[REDACTED]" + ], + "sms_center": "[REDACTED]", + "mcc": "460", + "mnc": "02", + "phone_number_is_manual": false, + "sms_center_is_manual": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/sim/instance-2--getSim.json b/packages/test-fixtures/src/simadmin/sim/instance-2--getSim.json new file mode 100644 index 0000000..db60712 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/sim/instance-2--getSim.json @@ -0,0 +1,31 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getSim", + "method": "GET", + "pathTemplate": "/api/sim", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "present": true, + "iccid": "[REDACTED]", + "imsi": "[REDACTED]", + "phone_numbers": [ + "[REDACTED]" + ], + "sms_center": "[REDACTED]", + "mcc": "460", + "mnc": "00", + "phone_number_is_manual": true, + "sms_center_is_manual": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/workmode-esim/instance-1--getEsimConfig.json b/packages/test-fixtures/src/simadmin/workmode-esim/instance-1--getEsimConfig.json new file mode 100644 index 0000000..406042d --- /dev/null +++ b/packages/test-fixtures/src/simadmin/workmode-esim/instance-1--getEsimConfig.json @@ -0,0 +1,17 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getEsimConfig", + "method": "GET", + "pathTemplate": "/api/esim/config", + "redacted": true, + "statusCategory": "unsupported", + "httpStatus": 404, + "contentType": "text/plain", + "latencyBucket": "<250ms", + "payload": { + "text": "[REDACTED]" + } +} diff --git a/packages/test-fixtures/src/simadmin/workmode-esim/instance-1--getEsimLpacStatus.json b/packages/test-fixtures/src/simadmin/workmode-esim/instance-1--getEsimLpacStatus.json new file mode 100644 index 0000000..5dc722c --- /dev/null +++ b/packages/test-fixtures/src/simadmin/workmode-esim/instance-1--getEsimLpacStatus.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getEsimLpacStatus", + "method": "GET", + "pathTemplate": "/api/esim/lpac/status", + "redacted": true, + "statusCategory": "auth-required", + "httpStatus": 403, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "error", + "message": "eSIM module is disabled in current work mode" + } +} diff --git a/packages/test-fixtures/src/simadmin/workmode-esim/instance-1--getWorkMode.json b/packages/test-fixtures/src/simadmin/workmode-esim/instance-1--getWorkMode.json new file mode 100644 index 0000000..b43f2d6 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/workmode-esim/instance-1--getWorkMode.json @@ -0,0 +1,22 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-1", + "operationId": "getWorkMode", + "method": "GET", + "pathTemplate": "/api/work-mode", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "mode": "sim", + "worker_running": false + } + } +} diff --git a/packages/test-fixtures/src/simadmin/workmode-esim/instance-2--getEsimConfig.json b/packages/test-fixtures/src/simadmin/workmode-esim/instance-2--getEsimConfig.json new file mode 100644 index 0000000..ebc8ce8 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/workmode-esim/instance-2--getEsimConfig.json @@ -0,0 +1,17 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getEsimConfig", + "method": "GET", + "pathTemplate": "/api/esim/config", + "redacted": true, + "statusCategory": "unsupported", + "httpStatus": 404, + "contentType": "text/plain", + "latencyBucket": "<250ms", + "payload": { + "text": "[REDACTED]" + } +} diff --git a/packages/test-fixtures/src/simadmin/workmode-esim/instance-2--getEsimLpacStatus.json b/packages/test-fixtures/src/simadmin/workmode-esim/instance-2--getEsimLpacStatus.json new file mode 100644 index 0000000..f7c0425 --- /dev/null +++ b/packages/test-fixtures/src/simadmin/workmode-esim/instance-2--getEsimLpacStatus.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getEsimLpacStatus", + "method": "GET", + "pathTemplate": "/api/esim/lpac/status", + "redacted": true, + "statusCategory": "auth-required", + "httpStatus": 403, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "error", + "message": "eSIM module is disabled in current work mode" + } +} diff --git a/packages/test-fixtures/src/simadmin/workmode-esim/instance-2--getWorkMode.json b/packages/test-fixtures/src/simadmin/workmode-esim/instance-2--getWorkMode.json new file mode 100644 index 0000000..a8df5ec --- /dev/null +++ b/packages/test-fixtures/src/simadmin/workmode-esim/instance-2--getWorkMode.json @@ -0,0 +1,22 @@ +{ + "schemaVersion": 1, + "upstreamBaseline": "58e2204", + "capturedAt": "2026-07-15", + "sourceInstanceAlias": "instance-2", + "operationId": "getWorkMode", + "method": "GET", + "pathTemplate": "/api/work-mode", + "redacted": true, + "statusCategory": "success", + "httpStatus": 200, + "contentType": "application/json", + "latencyBucket": "<250ms", + "payload": { + "status": "ok", + "message": "Success", + "data": { + "mode": "sim", + "worker_running": false + } + } +} diff --git a/packages/test-fixtures/src/verifier.ts b/packages/test-fixtures/src/verifier.ts new file mode 100644 index 0000000..54995ca --- /dev/null +++ b/packages/test-fixtures/src/verifier.ts @@ -0,0 +1,73 @@ +import { parseResponseSensitivePath } from './redactor.ts'; + +export type Shape={type:string,keys?:Record,items?:Shape[]}; + +export function payloadShape(value:any):Shape { + if(value===null)return {type:'null'}; + if(Array.isArray(value))return {type:'array',items:value.map(payloadShape)}; + if(typeof value==='object')return {type:'object',keys:Object.fromEntries(Object.keys(value).sort().map(k=>[k,payloadShape(value[k])]))}; + return {type:typeof value}; +} + +export function validateShapeNode(node:any):void { + if(!node||typeof node!=='object'||Array.isArray(node))throw new Error('invalid shape node'); + const allowed=node.type==='object'?['keys','type']:node.type==='array'?['items','type']:['type']; + if(!['object','array','string','number','boolean','null'].includes(node.type)||JSON.stringify(Object.keys(node).sort())!==JSON.stringify(allowed))throw new Error('invalid shape node'); + if(node.type==='object'){ + if(!node.keys||typeof node.keys!=='object'||Array.isArray(node.keys))throw new Error('invalid shape keys'); + for(const child of Object.values(node.keys))validateShapeNode(child); + } else if(node.type==='array'){ + if(!Array.isArray(node.items))throw new Error('invalid shape items'); + for(const child of node.items)validateShapeNode(child); + } +} + +function canonicalPrimitive(value:any){ + return value===null||value==='[REDACTED]'||(typeof value==='number'&&value===0)||(typeof value==='boolean'&&value===false); +} +function assertCanonicalTree(value:any):void { + if(Array.isArray(value)){for(const item of value)assertCanonicalTree(item);return;} + if(value&&typeof value==='object'){for(const item of Object.values(value))assertCanonicalTree(item);return;} + if(!canonicalPrimitive(value))throw new Error('non-canonical sensitive leaf'); +} +function matchedNodes(node:any,parts:string[],i=0):any[]{ + if(i===parts.length)return [node]; + if(parts[i]==='*')return Array.isArray(node)?node.flatMap(x=>matchedNodes(x,parts,i+1)):[]; + return node&&typeof node==='object'&&parts[i] in node?matchedNodes(node[parts[i]],parts,i+1):[]; +} +// Deliberately excludes ordinary `message`; only credential-like generic keys belong here. +const GENERIC_SENSITIVE_KEY=/(?:password|passwd|credential|api[_-]?key|access[_-]?(?:key|token|secret|id)|device[_-]?key|private[_-]?key|(?:^|[_-])pin(?:$|[_-])|puk|token|secret|cookie|authorization|confirmation[_-]?code)/i; +export function validateSensitivePayload(payload:any,operation:any):void { + for(const field of operation?.sensitiveFields||[]){ + if(field?.direction!=='response')continue; + for(const node of matchedNodes(payload,parseResponseSensitivePath(field.path)))assertCanonicalTree(node); + } + function walk(node:any):void{ + if(Array.isArray(node)){for(const x of node)walk(x);return;} + if(node&&typeof node==='object')for(const [key,value] of Object.entries(node)){if(GENERIC_SENSITIVE_KEY.test(key))assertCanonicalTree(value);else walk(value);} + } + walk(payload); +} + +const isJson=(s:any)=>typeof s==='string'&&(s==='application/json'||s.endsWith('+json')); +const exactPayload=(actual:any,expected:any)=>JSON.stringify(actual)===JSON.stringify(expected); +export function validateStatusContract(f:any):void { + const status=f.httpStatus,category=f.statusCategory; + if(category==='success'){ + if(!(Number.isInteger(status)&&status>=200&&status<300&&isJson(f.contentType)))throw new Error('inconsistent success status'); + }else if(category==='auth-required'){ + if(![401,403].includes(status))throw new Error('inconsistent auth status'); + }else if(category==='unsupported'){ + if(![404,405,501].includes(status))throw new Error('inconsistent unsupported status'); + }else if(category==='non-json'){ + const valid=Number.isInteger(status)&&status>=200&&status<300&&((!isJson(f.contentType)&&exactPayload(f.payload,{text:'[REDACTED]'}))||(isJson(f.contentType)&&exactPayload(f.payload,{error:'invalid-json'}))); + if(!valid)throw new Error('inconsistent non-json status'); + }else if(category==='http-error'){ + // Redirects are observed with redirect:'manual' and are non-success HTTP outcomes. + if(!(Number.isInteger(status)&&status>=300&&status<600&&![401,403,404,405,501].includes(status)))throw new Error('inconsistent http error status'); + }else if(category==='timeout'){ + if(status!==null||f.contentType!==null||f.latencyBucket!=='timeout'||!exactPayload(f.payload,{error:'timeout'}))throw new Error('inconsistent timeout status'); + }else if(category==='network-error'){ + if(status!==null||f.contentType!==null||f.latencyBucket==='timeout'||!exactPayload(f.payload,{error:'network-error'}))throw new Error('inconsistent network status'); + }else throw new Error('unknown status category'); +} \ No newline at end of file diff --git a/packages/test-fixtures/test/fixture-safety.test.ts b/packages/test-fixtures/test/fixture-safety.test.ts new file mode 100644 index 0000000..29d7e35 --- /dev/null +++ b/packages/test-fixtures/test/fixture-safety.test.ts @@ -0,0 +1,101 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { readFile, readdir, stat } from 'node:fs/promises'; +import { createHash } from 'node:crypto'; +import path from 'node:path'; +import { upstream58e2204Operations } from '../../operation-registry/src/upstream-58e2204.ts'; +import { collectOne, selectReadonlyOperations, validateReadonlyOperation, DENY_REASONS } from '../scripts/collector.ts'; +import { redact } from '../src/redactor.ts'; +import { payloadShape, validateShapeNode, validateSensitivePayload, validateStatusContract } from '../src/verifier.ts'; + +const root = path.resolve(import.meta.dirname, '..'); +const fixtureRoot = path.join(root, 'src/simadmin'); +const allowedEnvelope = ['schemaVersion','upstreamBaseline','capturedAt','sourceInstanceAlias','operationId','method','pathTemplate','statusCategory','httpStatus','contentType','latencyBucket','redacted','payload']; +// Preserve business-schema keys such as `url` and channel `headers`; sensitive values +// are typed-redacted. The exact top-level envelope already excludes transport metadata. +const forbiddenKeys = /^(raw(response)?|instance(id|name))$/i; +const DENIED_PATHS = new Set(Object.keys(DENY_REASONS)); +const leakPatterns = [ + /https?:\/\//i, /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i, + /\b(?:\d{1,3}\.){3}\d{1,3}\b/, /(?:[0-9a-f]{2}:){5}[0-9a-f]{2}/i, + /\+?\d(?:[ ()-]*\d){9,14}/, /\b\d{14,22}\b/, + /\b(?:bearer\s+)?[A-Za-z0-9_-]{32,}\b/i, +]; + +async function jsonFiles(dir:string):Promise { const out:string[]=[]; for(const e of await readdir(dir,{withFileTypes:true})){const p=path.join(dir,e.name); if(e.isDirectory()) out.push(...await jsonFiles(p)); else if(e.name.endsWith('.json')) out.push(p);} return out; } +function walkKeys(v:any, cb:(k:string)=>void){ if(Array.isArray(v)) return v.forEach(x=>walkKeys(x,cb)); if(v&&typeof v==='object') for(const [k,x] of Object.entries(v)){cb(k);walkKeys(x,cb);} } +function stringLeaves(v:any,out:string[]=[]){if(Array.isArray(v))v.forEach(x=>stringLeaves(x,out));else if(v&&typeof v==='object')Object.values(v).forEach(x=>stringLeaves(x,out));else if(typeof v==='string'&&v.length>=3)out.push(v);return out;} + +test('selector is registry-derived passive GET R0 only with explicit denials', () => { + const { selected, denied } = selectReadonlyOperations(upstream58e2204Operations); + assert.ok(selected.length > 20); + assert.ok(denied.some((x:any)=>x.pathTemplate==='/api/network/operators/scan' && x.denyReason)); + for(const op of selected){ assert.equal(op.method,'GET'); assert.equal(op.riskLevel,'R0'); assert.doesNotMatch(op.pathTemplate,/[{}]/); assert.notEqual(op.pathTemplate,'/api/network/operators/scan'); } +}); + +test('collector source has no write-method or authentication escape hatch', async () => { + const source = await readFile(path.join(root,'scripts/collect-readonly-fixtures.ts'),'utf8'); + assert.doesNotMatch(source, /ensureAuthenticated|login\s*\(|--method|--path|--origin/i); + assert.doesNotMatch(source, /['"](?:POST|PUT|PATCH|DELETE)['"]/); +}); + +test('transport can only receive credential-free GET, manual redirect and timeout', async () => { + let init:any; const fake=async (_url:any, i:any)=>{init=i; return new Response(JSON.stringify({phone:'+15551234567',message:'private',ip:'10.1.2.3'}),{status:200,headers:{'content-type':'application/json','set-cookie':'bad=1'}})}; + const op=upstream58e2204Operations.find(x=>x.operationId==='getHealth')!; + const f=await collectOne({origin:'http://192.168.1.2',alias:'instance-1'},op,fake as any); + assert.deepEqual({method:init.method,body:init.body,redirect:init.redirect,credentials:init.credentials},{method:'GET',body:undefined,redirect:'manual',credentials:'omit'}); + assert.deepEqual(init.headers, { accept: 'application/json' }); assert.ok(init.signal); + assert.equal(f.payload.phone,'[REDACTED]'); assert.equal(f.payload.message,'private'); assert.equal(f.payload.ip,'[REDACTED]'); +}); + +test('redactor covers sensitive keys and value patterns deterministically',()=>{ + const x=redact({password:'p',TOKEN:'t',content:'body',phone:'x',other:['+155****4567','+155****4567','a@b.example','https://private.example/x','aa:bb:cc:dd:ee:ff','2001:db8::1']}); + assert.equal(x.password,'[REDACTED]'); assert.equal(x.TOKEN,'[REDACTED]'); assert.equal(x.content,'[REDACTED]'); assert.equal(x.phone,'[REDACTED]'); + for(const p of leakPatterns) assert.doesNotMatch(JSON.stringify(x),p); +}); + +test('Registry operation identity also rejects in-place structural mutation',()=>{ + const op:any=upstream58e2204Operations.find(x=>x.operationId==='getHealth')!; + const original=structuredClone(op); + const mutations=[ + (x:any)=>x.sensitiveFields.push({direction:'response',path:'$.response.data.secret'}), + (x:any)=>{delete x.pathTemplate;}, + (x:any)=>{x.method='POST';}, + (x:any)=>{x.sensitiveFields='changed';}, + ]; + for(const mutate of mutations){ + try{mutate(op);assert.throws(()=>validateReadonlyOperation(op),/Registry integrity/);} + finally{for(const key of Object.keys(op))delete op[key];Object.assign(op,structuredClone(original));} + } + validateReadonlyOperation(op); +}); + +test('collector categorizes status and JSON parse outcomes consistently',async()=>{ + const op=upstream58e2204Operations.find(x=>x.operationId==='getHealth')!; + const run=(status:number,type:string,body:string|null)=>collectOne({origin:'http://192.168.1.2',alias:'instance-1'},op,async()=>new Response(body,{status,headers:{'content-type':type}})); + for(const [status,type,body,category] of [[200,'application/problem+json','{}','success'],[200,'application/json','bad','non-json'],[204,'text/plain',null,'non-json'],[401,'application/json','{}','auth-required'],[405,'application/json','{}','unsupported'],[500,'application/json','{}','http-error']] as const){ + const f=await run(status,type,body);assert.equal(f.statusCategory,category);validateStatusContract(f); + } + const redirect=await run(302,'application/json','{}');assert.equal(redirect.statusCategory,'http-error');validateStatusContract(redirect); + assert.throws(()=>validateStatusContract({statusCategory:'success',httpStatus:401,contentType:'application/json',payload:{},latencyBucket:'<250ms'})); +}); + +test('real fixtures satisfy envelope, registry, leak scan, and manifest integrity', async()=>{ + const manifest=JSON.parse(await readFile(path.join(root,'src/manifest.json'),'utf8'));assert.deepEqual(Object.keys(manifest).sort(),['domainCoverage','files','realFixtureCount','schemaVersion','shapeBaseline','syntheticFixtureCount','upstreamBaseline']); const files=(await jsonFiles(fixtureRoot)).filter(x=>!x.includes('/synthetic-errors/')); + const srcEntries=await readdir(path.join(root,'src'));assert.ok(!srcEntries.includes('synthetic-errors')); + const config=JSON.parse(await readFile(path.resolve(root,'../../config.json'),'utf8')); + const privateValues=stringLeaves(config); + const expected=selectReadonlyOperations(upstream58e2204Operations).selected; + assert.equal(files.length,expected.length*2); assert.equal(manifest.realFixtureCount,files.length);assert.equal(manifest.syntheticFixtureCount,0); + assert.equal(manifest.schemaVersion,1);assert.equal(manifest.upstreamBaseline,'58e2204'); + const shapePath=path.join(root,'src/response-shapes-58e2204.json');const shapeText=await readFile(shapePath,'utf8');const shapeBaseline=JSON.parse(shapeText); + assert.deepEqual(Object.keys(shapeBaseline).sort(),['schemaVersion','shapes','upstreamBaseline']);assert.equal(shapeBaseline.schemaVersion,1);assert.equal(shapeBaseline.upstreamBaseline,'58e2204');assert.equal(Object.keys(shapeBaseline.shapes).length,78); + assert.deepEqual(Object.keys(manifest.shapeBaseline).sort(),['path','sha256','size']);assert.equal(manifest.shapeBaseline.path,'src/response-shapes-58e2204.json');assert.equal(manifest.shapeBaseline.size,(await stat(shapePath)).size);assert.equal(manifest.shapeBaseline.sha256,createHash('sha256').update(shapeText).digest('hex'));assert.ok(!manifest.files.some((x:any)=>x.path===manifest.shapeBaseline.path)); + for(const node of Object.values(shapeBaseline.shapes))validateShapeNode(node); + const registry=new Map(upstream58e2204Operations.map(x=>[x.operationId,x])); const domains=new Map();const pairs=new Set(); + const disk=files.map(file=>path.relative(root,file)).sort();const listed=manifest.files.map((x:any)=>x.path).sort();assert.deepEqual(listed,disk);assert.equal(new Set(listed).size,listed.length); + for(const file of files){const text=await readFile(file,'utf8'); const f=JSON.parse(text); assert.deepEqual(Object.keys(f).sort(),[...allowedEnvelope].sort()); assert.equal(f.schemaVersion,1);assert.equal(f.upstreamBaseline,'58e2204');assert.match(f.capturedAt,/^20(?:2[4-9]|[3-9]\d)-\d{2}-\d{2}$/);assert.ok(!Number.isNaN(Date.parse(`${f.capturedAt}T00:00:00Z`)));assert.ok(['instance-1','instance-2'].includes(f.sourceInstanceAlias));assert.equal(f.redacted,true); assert.equal(f.method,'GET'); assert.ok(!('synthetic' in f));assert.ok(['success','non-json','auth-required','unsupported','http-error','timeout','network-error'].includes(f.statusCategory));if(['timeout','network-error'].includes(f.statusCategory))assert.equal(f.httpStatus,null);else assert.ok(Number.isInteger(f.httpStatus)); const op:any=registry.get(f.operationId);assert.ok(op);validateStatusContract(f);validateSensitivePayload(f.payload,op);const shapeKey=`${f.sourceInstanceAlias}::${f.operationId}`;assert.deepEqual(payloadShape(f.payload),shapeBaseline.shapes[shapeKey]); assert.equal(op?.riskLevel,'R0');assert.equal(op?.method,'GET'); assert.equal(op?.pathTemplate,f.pathTemplate);assert.ok(!DENIED_PATHS.has(f.pathTemplate));domains.set(op.upstreamDomain,(domains.get(op.upstreamDomain)||0)+1);const pair=`${f.sourceInstanceAlias}:${f.operationId}`;assert.ok(!pairs.has(pair));pairs.add(pair); walkKeys(f,k=>assert.doesNotMatch(k,forbiddenKeys)); for(const p of leakPatterns) assert.doesNotMatch(text,p); for(const value of privateValues) assert.ok(!text.includes(value),'fixture contains configured value'); const rel=path.relative(root,file); const m=manifest.files.find((x:any)=>x.path===rel); assert.ok(m); assert.equal(m.size,(await stat(file)).size);assert.match(m.sha256,/^[a-f0-9]{64}$/); assert.equal(m.sha256,createHash('sha256').update(text).digest('hex')); } + assert.deepEqual(Object.fromEntries([...domains].sort()),manifest.domainCoverage); + assert.deepEqual(Object.keys(shapeBaseline.shapes).sort(),[...pairs].map(x=>x.replace(':','::')).sort()); + assert.deepEqual([...pairs].sort(),expected.flatMap((op:any)=>['instance-1','instance-2'].map(alias=>`${alias}:${op.operationId}`)).sort()); +}); diff --git a/packages/test-fixtures/test/security-regressions.test.ts b/packages/test-fixtures/test/security-regressions.test.ts new file mode 100644 index 0000000..18f6d61 --- /dev/null +++ b/packages/test-fixtures/test/security-regressions.test.ts @@ -0,0 +1,90 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { upstream58e2204Operations } from '../../operation-registry/src/upstream-58e2204.ts'; +import { collectOne, selectReadonlyOperations, validateReadonlyOperation, validateInstanceOrigin } from '../scripts/collector.ts'; +import { loadInstances } from '../scripts/collect-readonly-fixtures.ts'; +import { redact, redactOperationPayload, parseResponseSensitivePath } from '../src/redactor.ts'; + +const health=upstream58e2204Operations.find((x:any)=>x.operationId==='getHealth')!; +const fakeResponse=async()=>new Response('{"ok":true}',{headers:{'content-type':'application/json'}}); + +test('operation validator rejects path and registry identity bypasses', async()=>{ + const attacks=['https://example.invalid/api/health','//example.invalid/api/health','/api/health?scan=1','/api/health#x','/api/%73can','/api/%252e%252e/health','/api/a/../health','/api\\health','/api//health']; + for(const pathTemplate of attacks) assert.throws(()=>validateReadonlyOperation({...health,pathTemplate})); + assert.throws(()=>validateReadonlyOperation({...health})); + assert.throws(()=>validateReadonlyOperation({operationId:health.operationId,method:'GET',riskLevel:'R0',pathTemplate:health.pathTemplate})); + await assert.rejects(()=>collectOne({origin:'http://192.168.1.2',alias:'instance-1'},{...health},fakeResponse)); +}); + +test('all path bypass classes fail before transport',async()=>{ + let calls=0;const transport=async()=>{calls++;return new Response('{}',{headers:{'content-type':'application/json'}})}; + const attacks=['https://evil.invalid/api/health','//evil.invalid/api/health','/api/health?q=1','/api/health#x','/api/%68ealth','/api/%252e%252e/x','/api/a/../x','/api\\health','/api//health']; + for(const pathTemplate of attacks) await assert.rejects(()=>collectOne({origin:'http://192.168.1.2',alias:'instance-1'},{...health,pathTemplate},transport)); + assert.equal(calls,0); + assert.throws(()=>selectReadonlyOperations([{...health}])); +}); + +test('collectOne validates RFC1918 origin before transport',()=>{ + for(const origin of ['http://127.0.0.1','http://169.254.1.1','http://100.100.100.200','http://8.8.8.8','http://router.local','http://u:p@192.168.1.2','http://192.168.1.2/x','http://192.168.1.2?q=1','ftp://192.168.1.2']) assert.throws(()=>validateInstanceOrigin(origin)); + assert.equal(validateInstanceOrigin('https://172.16.2.3:8443'),'https://172.16.2.3:8443'); +}); + +test('passive selection explicitly denies connectivity and active scan',()=>{ + const {selected,denied}=selectReadonlyOperations(upstream58e2204Operations); + assert.ok(denied.some((x:any)=>x.pathTemplate==='/api/connectivity')); + assert.ok(denied.some((x:any)=>x.pathTemplate==='/api/network/operators/scan')); + assert.ok(!selected.some((x:any)=>x.pathTemplate==='/api/connectivity')); +}); + +test('config uses formal validation plus collector LAN/auth/origin constraints',()=>{ + const good={instances:[{id:'a',url:'http://192.168.1.2',auth:{mode:'none'}},{id:'b',url:'https://10.0.0.2',auth:{mode:'none'}}]}; + assert.deepEqual(loadInstances(good).map((x:any)=>x.alias),['instance-1','instance-2']); + const bad=['http://127.0.0.1','http://169.254.1.2','http://100.100.100.200','http://8.8.8.8','http://router.local','http://u:***@192.168.1.2','http://192.168.1.2/path','http://192.168.1.2?q=1','http://192.168.1.2#x','http://[::1]']; + for(const url of bad) assert.throws(()=>loadInstances({instances:[{id:'a',url},{id:'b',url:'http://10.0.0.2'}]})); + assert.throws(()=>loadInstances({instances:[{id:'a',url:'http://192.168.1.2',auth:{password:'x'}},{id:'b',url:'http://10.0.0.2'}]})); + assert.throws(()=>loadInstances({instances:[{id:'a',url:'http://192.168.1.2'}]})); + assert.throws(()=>loadInstances({instances:[{id:'a',url:'http://192.168.1.2'},{id:'b',url:'http://10.0.0.2'},{id:'c',url:'http://10.0.0.3'}]})); +}); + +test('directional response JSONPaths redact every declared path and preserve shape/types',()=>{ + const ops=upstream58e2204Operations.filter((op:any)=>op.sensitiveFields.some((f:any)=>f.direction==='response')); + assert.ok(ops.length>0); + for(const op of ops) for(const field of op.sensitiveFields.filter((f:any)=>f.direction==='response')){ + const parts=parseResponseSensitivePath(field.path); assert.ok(parts.length>0,`${op.operationId} unsupported response path`); + let leaf:any={s:'private',n:42,b:true,z:null,a:['x',{q:9}]}; + let payload:any=leaf; + for(let i=parts.length-1;i>=0;i--){const p=parts[i]; payload=p==='*'?[payload]:{[p]:payload};} + const out:any=redactOperationPayload(payload,op); + let hit=out; for(const p of parts) hit=p==='*'?hit[0]:hit[p]; + assert.deepEqual(hit,{s:'[REDACTED]',n:0,b:false,z:null,a:['[REDACTED]',{q:0}]}); + } +}); + +test('deep sanitizer handles reviewed key/value bypasses without schema destruction',()=>{ + const input:any={credential:'x',api_key:'x',access_key:'x',device_key:'x',private_key:'x',pin:12,puk:34,username:'x',user:'x',account:'x',serial:'x',revision:'x',path:'/private/a',template:'user=x token=abc123 path=/private/a',config:{access_token:'tiny'},phone_number_is_manual:true,sms_center_is_manual:false,message:'API is healthy',nested:'{"username":"x","enabled":true}',host:'private.internal:8080',short_number:'12345678',split_id:'12-34-56-78-90-12-34',ipv6:'::1%lo0',latitude:1.234567,lon:2.345678,cell_id:99,lac:2,tac:3,pci:4,enb:5,gnb:6,uptime:777,traffic:888,timestamp:'2026-07-16T12:34:56Z',unknown:'AKIAIOSFODNN7EXAMPLE'}; + const x:any=redact(input); + for(const k of ['credential','api_key','access_key','device_key','private_key','username','user','account','serial','revision','path','template','host','short_number','split_id','ipv6','timestamp','unknown']) assert.equal(x[k],'[REDACTED]'); + for(const k of ['pin','puk','latitude','lon','cell_id','lac','tac','pci','enb','gnb','uptime','traffic']) assert.equal(x[k],0); + assert.equal(typeof x.nested,'string'); assert.deepEqual(JSON.parse(x.nested),{username:'[REDACTED]',enabled:true}); + assert.deepEqual(x.config,{access_token:'[REDACTED]'}); assert.equal(x.phone_number_is_manual,true); assert.equal(x.sms_center_is_manual,false); assert.equal(x.message,'API is healthy'); +}); + +test('schema shapes and primitive types survive conservative redaction',()=>{ + const x:any=redact({phone_numbers:['12345678','87654321'],ip_addresses:[{v4:'192.168.1.9',active:true}],urls:['private.example/x'],webhook:{url:'//private.example/h',enabled:true},config:{s:'secret',n:42,b:true,z:null,a:['x',{n:9}]}}); + assert.ok(Array.isArray(x.phone_numbers));assert.equal(x.phone_numbers.length,2); + assert.ok(Array.isArray(x.ip_addresses));assert.equal(typeof x.ip_addresses[0],'object'); + assert.ok(Array.isArray(x.urls));assert.equal(typeof x.webhook,'object'); + assert.deepEqual(x.config,{s:'[REDACTED]',n:0,b:false,z:null,a:['[REDACTED]',{n:0}]}); +}); + +test('invalid declared JSON and non-JSON bodies are non-json and discarded',async()=>{ + const invalid=await collectOne({origin:'http://192.168.1.2',alias:'instance-1'},health,async()=>new Response('{bad',{status:200,headers:{'content-type':'application/json'}})); + assert.equal(invalid.statusCategory,'non-json');assert.deepEqual(invalid.payload,{error:'invalid-json'}); + const text=await collectOne({origin:'http://192.168.1.2',alias:'instance-1'},health,async()=>new Response('private body',{status:200,headers:{'content-type':'text/plain'}})); + assert.equal(text.statusCategory,'non-json');assert.deepEqual(text.payload,{text:'[REDACTED]'}); +}); + +test('collector errors never echo rejected origin values',async()=>{ + const secret='http://user:password@evil.invalid/private?token=x'; + try{await collectOne({origin:secret,alias:'instance-1'},health,fakeResponse);assert.fail('expected rejection');}catch(error:any){assert.ok(!String(error.message).includes(secret));assert.ok(!String(error.message).includes('password'));} +});