From 1298ecc194e6b564fdb4e0e8dc2fdf03b9b179da Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 10 Nov 2026 17:39:00 -0500 Subject: [PATCH] test: reproduce native import retention without managed caller --- .../native-retention/NATIVE_IMPORT.md | 119 +++++++++++++ .../native-retention/NATIVE_IMPORT_DESIGN.md | 26 +++ .../native-retention/NativeImportControl.c | 58 ++++--- .../native-retention/README.md | 7 + .../fixture-before-harness-cleanup.json | 3 + .../fixture-cleanup.json | 29 ++++ .../native-build.log | 37 ++++ .../provenance.json | 60 +++++++ .../result.json | 160 ++++++++++++++++++ .../seed-build.log | 9 + .../seed.jsonl | 1 + .../selected-samples.jsonl | 9 + .../verification.json | 48 ++++++ .../native-retention/native_import.py | 82 ++++++++- 14 files changed, 619 insertions(+), 29 deletions(-) create mode 100644 scripts/validation/opcua-lifecycle-memory/native-retention/NATIVE_IMPORT.md create mode 100644 scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/fixture-before-harness-cleanup.json create mode 100644 scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/fixture-cleanup.json create mode 100644 scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/native-build.log create mode 100644 scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/provenance.json create mode 100644 scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/result.json create mode 100644 scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/seed-build.log create mode 100644 scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/seed.jsonl create mode 100644 scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/selected-samples.jsonl create mode 100644 scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/verification.json diff --git a/scripts/validation/opcua-lifecycle-memory/native-retention/NATIVE_IMPORT.md b/scripts/validation/opcua-lifecycle-memory/native-retention/NATIVE_IMPORT.md new file mode 100644 index 00000000..75f6e028 --- /dev/null +++ b/scripts/validation/opcua-lifecycle-memory/native-retention/NATIVE_IMPORT.md @@ -0,0 +1,119 @@ +# Installed native bridge import reproduces AppleDatabase retention + +The corrected fixed-200 diagnostic reproduced the native heap inventory growth +**without a managed caller in the measured process**. With the exact installed +.NET Apple cryptography bridge still loaded, `Security::AppleDatabase` rose from +**1 to 201 objects** and stayed at 201 after five seconds idle. All observed +returned CF references balanced, native delete statuses were zero, and numeric +FD counts and owned keychain files/FDs stayed flat. The native bridge plus Apple +import/keychain path is sufficient in this control; managed .NET and the OPC UA +SDK are not required in the measured process. + +This does not identify the retaining native owner or separate bridge-native +ownership from Apple caching. A classified heap object is not an open handle, +and its shallow bytes do not explain the full RSS change. The control provides +no production mitigation, budget waiver, full-soak/G4 pass or #799 closure. + +## Controlled sequence and actual ownership + +The measured arm ran once in a fresh private root on macOS **26.5.2** build +**25F84** arm64. Its C child hash-checked and loaded the exact installed native +bridge, verified its export image and rejected CLR/SDK images. The separate +.NET **10.0.14** SDK **2.0.1** seed made a normal RSA application fixture, verified +its private key against the public leaf, disposed the SDK manager, wrote private +mode-0600 inputs under a mode-0700 directory and exited before the measured child. +The seed's SDK PKI was removed before native measurement. The child consumed +public DER and PKCS1 private key bytes, not a PFX, and did not emulate managed +PFX parsing, matching or finalizer timing. The explicit legacy-key release was +after identity disposal. [The design](NATIVE_IMPORT_DESIGN.md) maps the actual +installed binary ABI, native exports and wrapper copy/release sequence. + +The native child performed the pinned bridge's DER certificate import, modern +RSA key creation/public copy/external representation, ephemeral legacy private +key import, private keychain move/identity lookup and identity certificate copy. +Every operation exercised nine ordered wrapper keychain-copy calls. The logical +owner model counted only observed non-null copies whose type, pointer and +private generated path matched the initial native keychain. The collector +independently replayed those owner transitions and reconciled actual deletion +stage and returned CF output counts. No logical owner was invented for a null +copy. Any previously tracked item losing its association would fail the run. + +All **200** moves and identity certificate copies succeeded. Native keychain +create/path/set-never-lock/delete and the reached native OSStatus outputs were +zero. The bridge operations that use return value one did return one. Both +first/last returned certificate identity checks matched the unchanged seed leaf. +All **1,800** wrapper copies had bridge-normalized status zero. Four calls per +operation returned an owned private keychain reference: post-move original cert +Track, copied cert Track, original cert Untrack and copied cert Untrack. The +other five calls returned null, including both identity calls. All **800** +returned keychain copies were released. Across all outputs the ledger was +**2,402 acquired / 2,402 released**, including **200/200** initial keychain refs. +There were no fallback cleanups or remaining logical owners. + +In all 200 operations, the original cert was released, then the initial +import-state logical owner was relinquished. Deletion occurred inside the final +**copied-certificate Untrack**, while that keychain copy, copied certificate, +identity and legacy key references were still alive. The native delete returned +zero, then the initial native keychain owner, copied keychain ref and copied +certificate were released in order. The identity's subsequent Untrack returned +no keychain association. This observed order differs from the fixed identity +association wrongly assumed by [attempt A](NATIVE_IMPORT_ATTEMPT.md), which +stopped during its first operation and remains preserved separately. + +## Native observations and cleanup + +| Checkpoint | AppleDatabase count / shallow bytes | Numeric FDs | Owned keychain files / FDs | RSS bytes | +|---|---:|---:|---:|---:| +| Before | 1 / 768 | 3 | 0 / 0 | 7,749,632 | +| First | 2 / 1,536 | 3 | 0 / 0 | 10,862,592 | +| 200 | 201 / 154,368 | 3 | 0 / 0 | 14,598,144 | +| Five-second idle | 201 / 154,368 | 3 | 0 / 0 | 14,614,528 | + +Default and search-list fingerprints were equal before and after, with all +query statuses zero and search-list count two. Four owned query copies were +released; no setter or restore API was called. All temporary private keychains +were generated with unrelated filenames, prompt disabled, and path-verified +before deletion. There were zero owned keychain files before harness cleanup. +Both builds, seed and measured process exited zero and were reaped. The remaining +private fixture files were overwritten and unlinked only after reaping; the task +root was removed. No physical secure-erasure guarantee is claimed. + +Native child time was **16.772 seconds**, parent time including probes **17.022 +seconds**. Heap probes were `heap --noContent -s`, numeric descriptors from +`lsof`, and RSS from Mach task info. Parent and child checkpoints use a +180-second limit, with separate bounded probe and process-reap overhead. The +C build succeeded with **six unsuppressed deprecation warnings** for the legacy +public keychain APIs it exercises. The seed build had zero warnings/errors. + +The [empty native keychain control](PURE_APPLE.md) stayed at one database object +throughout its 200 operations, so empty create/delete/release alone was +insufficient. The [SDK configured-store A/B](README.md) reproduced inventory +growth despite its observed SDK and managed owner release. This native import +control narrows that observation to the installed native bridge plus +Security.framework path. It does not assign a particular .NET, SDK or Apple +defect, establish native delete status for the separate managed A/B, or show +that a public-Apple-only import sequence reproduces the result. + +## Pinned evidence + +The unchanged private raw result is `/tmp/opcua2-native-import-20261110b`. +[Selected receipts and hashes](evidence/2026-11-10-native-import-attempt-b/verification.json) +retain build logs, provenance, seed and cleanup receipts, and a subset of the +207 exact raw JSONL rows. Full raw heap/FD inventories and all 200 operation +rows remain local. There is no retained private fixture. Source, installed +bridge, native executable and seed DLL hashes are in the provenance. + +- Result JSON SHA-256: `73771e5aea164d0207a1096d3a9ecb92603166a82a905dfc6860598b0b37f8b1` +- Full raw JSONL SHA-256: `350f35e46e159424c5e552b90e3b4a3a46d572d7ba034df274cd1646636e7498` +- Native executable SHA-256: `6a0d0d1980b505c20b5b270c8e3eceb6d0256b6b8953fbc2dad4b6f66db732cf` +- Seed DLL SHA-256: `bc9ea0f2ee2e6bd004bb2ecb801cbc4b1cbc250b1267bf31616d1f334a102893` + +The fixed collector invocation requires the pinned binary set and a fresh +private output. Any further run needs its own scope and serialization review. + +```sh +PYTHONDONTWRITEBYTECODE=1 python3 \ + scripts/validation/opcua-lifecycle-memory/native-retention/native_import.py \ + --references /tmp/opcua2-native-reload-20261110a/bin/Release/net10.0 \ + --output /tmp/opcua2-native-import-FRESH +``` diff --git a/scripts/validation/opcua-lifecycle-memory/native-retention/NATIVE_IMPORT_DESIGN.md b/scripts/validation/opcua-lifecycle-memory/native-retention/NATIVE_IMPORT_DESIGN.md index 6e23e33f..830686a0 100644 --- a/scripts/validation/opcua-lifecycle-memory/native-retention/NATIVE_IMPORT_DESIGN.md +++ b/scripts/validation/opcua-lifecycle-memory/native-retention/NATIVE_IMPORT_DESIGN.md @@ -177,3 +177,29 @@ from Apple caching; a later independently owned public-Apple sequence could be justified then. A flat result would not by itself prove a managed bug: omitted managed parsing/matching, registry bookkeeping or lifetime differences remain. No production implementation or additional experiment is approved by this design. + +## Association-driven correction after attempt A + +Attempt A's exact original source is preserved with its failed receipts. The +revised child retains all nine native wrapper copies but treats successful null +results as unassociated, as the installed TrackItem does. Only non-null copies +whose type, pointer and private generated path match the owned keychain create a +logical owner. A previously tracked item's missing association at release fails; +no owner is silently decremented. A copy of a retired keychain cannot consume a +registry owner. Explicit fallback cleanup remains a failed diagnostic outcome. + +The initial import-state owner is still released after original-certificate +disposal. The actual last owner determines when the native delete and original +CFRelease happen: import-state release if no item owner remains, otherwise the +actual final tracked-item Untrack while its copy and item references remain +alive. The receipt records that exact stage, live CF ownership at delete, and +each copy's logical owner/native owner state before and after. The collector +independently reconstructs the transitions from observed associations; it does +not assume identity/copied-cert association or a fixed non-null count. Leaf +identity checks remain first/last, and all returned CF outputs must reconcile. + +This correction changes only the diagnostic ownership model. It does not alter +the pinned bridge, imported material, fixed count, native calls, limits, +permissions, cleanup, or production. The corrected code passed a separate Astra gate and coordinator serialization +clearance before one fresh fixed-200 attempt. [Attempt B results](NATIVE_IMPORT.md) +record its actual association/deletion order and native inventory outcome. diff --git a/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c b/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c index 0f07b8f9..02996753 100644 --- a/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c +++ b/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c @@ -130,13 +130,19 @@ static void load_bridge(const char *path){ #undef LOAD image_guard(); } -struct copy_result {const char *stage;int32_t status;int present,associated;}; +struct copy_result { + const char *stage,*action;int32_t status;int present,associated; + unsigned owners_before,owners_after;int native_owner_before,native_owner_after; +}; struct operation_state { SecCertificateRef cert,copied;SecIdentityRef identity;SecKeyRef modern,public_key,legacy; CFDataRef external;SecKeychainRef keychain,keychain_identity,outer;CFErrorRef error; char path[PATH_MAX],backing[PATH_MAX]; unsigned logical_owners;int initial_owner,cert_tracked,copied_tracked,identity_tracked; - int failed,path_verified,deleted,delete_during_identity_untrack,fallback_cleanup; + int failed,path_verified,deleted,fallback_cleanup,import_state_released,leaf_checked,leaf_matches; + unsigned import_owners_before,import_owners_after; + const char *delete_stage; + int delete_copy_live,delete_cert_live,delete_copied_live,delete_identity_live,delete_legacy_live; int32_t cert_return,cert_status,modern_return,create_status,lock_status,external_return,key_return,key_status,move_return,move_status,copy_cert_status,delete_status,path_status; CFIndex modern_error,external_error;int modern_error_present,external_error_present;unsigned copy_count; struct copy_result copies[16]; @@ -146,18 +152,19 @@ static int private_path(struct operation_state *s,SecKeychainRef keychain){ char actual[PATH_MAX];memset(actual,0,sizeof(actual));int32_t status=keychain_path(keychain,actual); return status==0 && (!strcmp(actual,s->path)||!strcmp(actual,s->backing)); } -static void delete_owner(struct operation_state *s,const char *stage){ +static void delete_owner(struct operation_state *s,const char *stage,int copy_live){ if(!s->keychain)return; if(s->deleted){s->failed=1;return;} s->path_verified=private_path(s,s->keychain); if(s->path_verified){s->delete_status=delete_chain(s->keychain);s->deleted=1;} if(!s->path_verified||s->delete_status)s->failed=1; - s->delete_during_identity_untrack=!strcmp(stage,"release-identity")&&s->identity!=NULL&&s->copied==NULL; + s->delete_stage=stage;s->delete_copy_live=copy_live;s->delete_cert_live=s->cert!=NULL; + s->delete_copied_live=s->copied!=NULL;s->delete_identity_live=s->identity!=NULL;s->delete_legacy_live=s->legacy!=NULL; DROP(s->keychain);released_refs++; } -static void relinquish(struct operation_state *s,const char *stage){ +static void relinquish(struct operation_state *s,const char *stage,int copy_live){ if(!s->logical_owners){s->failed=1;return;} - if(--s->logical_owners==0)delete_owner(s,stage); + if(--s->logical_owners==0)delete_owner(s,stage,copy_live); } static SecKeychainRef copied_chain(struct operation_state *s,CFTypeRef item,const char *stage,int *associated){ *associated=0;if(!item)return NULL; @@ -165,20 +172,29 @@ static SecKeychainRef copied_chain(struct operation_state *s,CFTypeRef item,cons SecKeychainRef result=NULL;int32_t status=copy_chain(item,&result);owned(result); int type_ok=!result||CFGetTypeID(result)==SecKeychainGetTypeID(); int belongs=result&&type_ok&&s->keychain_identity==result&&private_path(s,result); - if(s->copy_count<16)s->copies[s->copy_count++]=(struct copy_result){stage,status,result!=NULL,belongs};else s->failed=1; + if(s->copy_count<16)s->copies[s->copy_count++]=(struct copy_result){stage,"lookup",status,result!=NULL,belongs, + s->logical_owners,s->logical_owners,s->keychain!=NULL,s->keychain!=NULL};else s->failed=1; if(status || !type_ok || (result&&!belongs))s->failed=1; *associated=status==0&&belongs;return result; } +static void record_copy_action(struct operation_state *s,unsigned index,const char *action){ + if(s->copy_count==index+1){struct copy_result *copy=&s->copies[index];copy->action=action; + copy->owners_after=s->logical_owners;copy->native_owner_after=s->keychain!=NULL;} +} static void track(struct operation_state *s,CFTypeRef item,const char *stage,int *tracked){ - int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated); + unsigned index=s->copy_count;int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated); + // Installed TrackItem does nothing for a null copy; never invent an owner. if(associated){if(*tracked||!s->keychain)s->failed=1;else{s->logical_owners++;*tracked=1;}} - DROP(copy); + record_copy_action(s,index,"track");DROP(copy); } static void untrack(struct operation_state *s,CFTypeRef item,const char *stage,int *tracked){ if(!item)return; - int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated); - if(*tracked){if(associated){*tracked=0;relinquish(s,stage);}else s->failed=1;} - else if(associated)s->failed=1; + unsigned index=s->copy_count;int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated); + if(*tracked){if(associated){*tracked=0;relinquish(s,stage,copy!=NULL);}else s->failed=1;} + // A still-registered private keychain must never consume an untracked owner. + // After deletion the installed managed registry has no entry to release. + else if(associated&&s->keychain)s->failed=1; + record_copy_action(s,index,"untrack"); // Final logical-owner release above precedes this copy's CFRelease. DROP(copy); } @@ -222,23 +238,25 @@ static void import_operation(unsigned iteration,const unsigned char *der,size_t if(s.failed)goto cleanup; s.move_return=move_key(s.cert,s.keychain,s.legacy,&s.identity,&s.move_status);owned(s.identity); track(&s,s.cert,"move-cert-track",&s.cert_tracked);track(&s,s.identity,"move-identity-track",&s.identity_tracked);DROP(s.outer); - if(s.move_return!=1||s.move_status||!s.identity||CFGetTypeID(s.identity)!=SecIdentityGetTypeID()||!s.cert_tracked||!s.identity_tracked||s.failed){s.failed=1;goto cleanup;} + if(s.move_return!=1||s.move_status||!s.identity||CFGetTypeID(s.identity)!=SecIdentityGetTypeID()||s.failed){s.failed=1;goto cleanup;} s.copy_cert_status=copy_cert(s.identity,&s.copied);owned(s.copied);track(&s,s.copied,"identity-cert-track",&s.copied_tracked); - if(s.copy_cert_status||!s.copied||CFGetTypeID(s.copied)!=SecCertificateGetTypeID()||!s.copied_tracked||s.failed){s.failed=1;goto cleanup;} - if((iteration==1||iteration==REPETITIONS)&&!leaf_equal(s.copied,der,der_length)){s.failed=1;goto cleanup;} + if(s.copy_cert_status||!s.copied||CFGetTypeID(s.copied)!=SecCertificateGetTypeID()||s.failed){s.failed=1;goto cleanup;} + if(iteration==1||iteration==REPETITIONS){s.leaf_checked=1;s.leaf_matches=leaf_equal(s.copied,der,der_length); + if(!s.leaf_matches){s.failed=1;goto cleanup;}} cleanup: wipe(password,sizeof(password));DROP(s.error);DROP(s.external);DROP(s.modern);DROP(s.public_key);DROP(s.outer); untrack(&s,s.cert,"release-original-cert",&s.cert_tracked);DROP(s.cert); - if(s.initial_owner){s.initial_owner=0;relinquish(&s,"release-import-state");} + if(s.initial_owner){s.initial_owner=0;s.import_state_released=1;s.import_owners_before=s.logical_owners; + relinquish(&s,"release-import-state",0);s.import_owners_after=s.logical_owners;} untrack(&s,s.copied,"release-copied-cert",&s.copied_tracked);DROP(s.copied); untrack(&s,s.identity,"release-identity",&s.identity_tracked);DROP(s.identity); DROP(s.legacy); // Explicit lifetime; managed helper does not scope this local with using. - if(s.keychain){s.failed=1;s.fallback_cleanup=1;delete_owner(&s,"failure-fallback-after-items");} + if(s.keychain){s.failed=1;s.fallback_cleanup=1;delete_owner(&s,"failure-fallback-after-items",0);} unsigned made=all_created-before_created,released=all_released-before_released; if(made!=released||s.logical_owners||s.cert_tracked||s.copied_tracked||s.identity_tracked)s.failed=1; - if(!s.failed&&(s.copy_count!=9||!s.delete_during_identity_untrack||!s.deleted))s.failed=1; - fprintf(stdout,"{\"kind\":\"operation\",\"iteration\":%u,\"certReturn\":%d,\"certStatus\":%d,\"modernReturn\":%d,\"modernErrorCode\":%ld,\"modernErrorPresent\":%s,\"createStatus\":%d,\"pathStatus\":%d,\"neverLockStatus\":%d,\"externalReturn\":%d,\"externalErrorCode\":%ld,\"externalErrorPresent\":%s,\"legacyReturn\":%d,\"legacyStatus\":%d,\"moveReturn\":%d,\"moveStatus\":%d,\"copyCertStatus\":%d,\"deleteStatus\":%d,\"privatePathVerified\":%s,\"deleteDuringFinalIdentityUntrack\":%s,\"fallbackCleanup\":%s,\"logicalOwnersRemaining\":%u,\"ownedOutputs\":%u,\"releasedOutputs\":%u,\"failed\":%s,\"copies\":[",iteration,s.cert_return,s.cert_status,s.modern_return,(long)s.modern_error,s.modern_error_present?"true":"false",s.create_status,s.path_status,s.lock_status,s.external_return,(long)s.external_error,s.external_error_present?"true":"false",s.key_return,s.key_status,s.move_return,s.move_status,s.copy_cert_status,s.delete_status,s.path_verified?"true":"false",s.delete_during_identity_untrack?"true":"false",s.fallback_cleanup?"true":"false",s.logical_owners,made,released,s.failed?"true":"false"); - for(unsigned i=0;i/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:41:42: warning: 'SecKeychainGetTypeID' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations] + 41 | if(!keychain||CFGetTypeID(keychain)!=SecKeychainGetTypeID())return errSecParam; + | ^ +/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:270:10: note: 'SecKeychainGetTypeID' has been explicitly marked deprecated here + 270 | CFTypeID SecKeychainGetTypeID(void) + | ^ +/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:43:21: warning: 'SecKeychainGetPath' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations] + 43 | OSStatus status=SecKeychainGetPath(keychain,&length,path); + | ^ +/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:474:10: note: 'SecKeychainGetPath' has been explicitly marked deprecated here + 474 | OSStatus SecKeychainGetPath(SecKeychainRef __nullable keychain, UInt32 *ioPathLength, char *pathName) + | ^ +/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:54:29: warning: 'SecKeychainCopyDefault' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations] + 54 | OSStatus default_status=SecKeychainCopyDefault(&default_keychain); + | ^ +/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:384:10: note: 'SecKeychainCopyDefault' has been explicitly marked deprecated here + 384 | OSStatus SecKeychainCopyDefault(SecKeychainRef * __nonnull CF_RETURNS_RETAINED keychain) + | ^ +/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:58:28: warning: 'SecKeychainCopySearchList' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations] + 58 | OSStatus search_status=SecKeychainCopySearchList(&search); + | ^ +/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:404:10: note: 'SecKeychainCopySearchList' has been explicitly marked deprecated here + 404 | OSStatus SecKeychainCopySearchList(CFArrayRef * __nonnull CF_RETURNS_RETAINED searchList) + | ^ +/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:151:42: warning: 'SecKeychainGetTypeID' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations] + 151 | if(!keychain||CFGetTypeID(keychain)!=SecKeychainGetTypeID())return 0; + | ^ +/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:270:10: note: 'SecKeychainGetTypeID' has been explicitly marked deprecated here + 270 | CFTypeID SecKeychainGetTypeID(void) + | ^ +/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:173:47: warning: 'SecKeychainGetTypeID' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations] + 173 | int type_ok=!result||CFGetTypeID(result)==SecKeychainGetTypeID(); + | ^ +/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:270:10: note: 'SecKeychainGetTypeID' has been explicitly marked deprecated here + 270 | CFTypeID SecKeychainGetTypeID(void) + | ^ +6 warnings generated. diff --git a/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/provenance.json b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/provenance.json new file mode 100644 index 00000000..419bc36d --- /dev/null +++ b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/provenance.json @@ -0,0 +1,60 @@ +{ + "sourcesSha256": { + "NativeImportControl.c": "ed442bacbdbbc3d420864c4b8ddac9bb4a5799d1e1a1e67d33033678e8401648", + "ImportSeed.cs": "feaac1c93bdb0f4e59bd0a9fb213d6de53cb89ece7393356c9d12d318b395c1b", + "native_import.py": "fc4092ab69a9a8b8213697d83c171632248c84c5c4bcbcf59ea6d2faffa82189", + "pure_apple.py": "1b2148f1c20578529355379ab94b439931d7241608a5d5effce8fc86f4af7bc6" + }, + "nativeBridgeSha256": "0333994e217a3d111d36d7f31460eea69a286f9fc819e2d7c746df13d2aec46c", + "managedCryptographySha256": "f4957d7218a004a27bf8964e45147df6a88092c6e7344582082840d62c6c579a", + "sdkSeedSha256": { + "Opc.Ua.Client.dll": "620da406fabdbc75d11f9827ea7e39d2d3c762471bd2264b0d11f1d6cd9247cd", + "Opc.Ua.Configuration.dll": "6ed6a594c93c3ff35d1a16539a9fe87c1e2640549cc2f48ed6bae333dc8bf0e7", + "Opc.Ua.Core.Schema.dll": "51cfad48657d95d38074bb88be29aea6f5b361a07397247d58838d066b99772e", + "Opc.Ua.Core.Types.dll": "a7dd141b8dabe8848ff28c2fb8e16a85a0508e6a49e6b1a1c1e267175b99af96", + "Opc.Ua.Core.dll": "9d0857aa6b7f3c49037d4ea557b4da8edf07e146069464481783e66c5c9cd35a", + "Opc.Ua.Security.Certificates.dll": "7f4969aceb2f0db5328c6882cb4b117342f3b18905c38acdba600683860c4fd0", + "Opc.Ua.Server.dll": "930e714a2f6e15d393840bcdc95e1afa8012bc740c3738a655f958142721864e", + "Opc.Ua.Types.dll": "c542f69882f4e8a4ebd5ccc28a3881d6967c7ffb6dcc3c56dc6c776f39c2ede1" + }, + "compileCommand": [ + "clang", + "-std=c11", + "-O0", + "-g", + "-Wall", + "-Wextra", + "/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c", + "-framework", + "Security", + "-framework", + "CoreFoundation", + "-o", + "/private/tmp/opcua2-native-import-20261110b/NativeImportControl" + ], + "compiler": "Apple clang version 21.0.0 (clang-2100.0.123.102)\nTarget: arm64-apple-darwin25.5.0\nThread model: posix\nInstalledDir: /Library/Developer/CommandLineTools/usr/bin\n", + "os": "ProductName:\t\tmacOS\nProductVersion:\t\t26.5.2\nBuildVersion:\t\t25F84\n", + "architecture": "arm64", + "hostDotnet": ".NET SDK:\n Version: 10.0.403\n Commit: 5a2162bea6\n Workload version: 10.0.400-manifests.a00bebb6\n MSBuild version: 18.9.15+5a2162bea\n\nRuntime Environment:\n OS Name: Mac OS X\n OS Version: 26.5\n OS Platform: Darwin\n RID: osx-arm64\n Base Path: /opt/homebrew/Cellar/dotnet/10.0.403/libexec/sdk/10.0.403/\n\n.NET workloads installed:\nThere are no installed workloads to display.\nConfigured to use workload sets when installing new manifests.\nNo workload sets are installed. Run \"dotnet workload restore\" to install a workload set.\n\nHost:\n Version: 10.0.14\n Architecture: arm64\n Commit: 0427b9abbe\n\n.NET SDKs installed:\n 10.0.403 [/opt/homebrew/Cellar/dotnet/10.0.403/libexec/sdk]\n\n.NET runtimes installed:\n Microsoft.AspNetCore.App 10.0.14 [/opt/homebrew/Cellar/dotnet/10.0.403/libexec/shared/Microsoft.AspNetCore.App]\n Microsoft.NETCore.App 10.0.14 [/opt/homebrew/Cellar/dotnet/10.0.403/libexec/shared/Microsoft.NETCore.App]\n\nOther architectures found:\n None\n\nEnvironment variables:\n Not set\n\nglobal.json file:\n /.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/global.json\n\nLearn more:\n https://aka.ms/dotnet/info\n\nDownload .NET:\n https://aka.ms/dotnet/download\n", + "repetitions": 200, + "stages": [ + "before", + "first", + "repeated", + "idle" + ], + "idleSeconds": 5, + "fullSoakGate": false, + "managedCallerInMeasuredChild": false, + "managedPfxParsingEmulated": false, + "legacyKeyLifetime": "Explicit CFRelease after identity disposal; managed local has no explicit using scope.", + "wrapperNativeCopyCallsPerOperation": 9, + "logicalOwnersFromObservedPrivateAssociationsOnly": true, + "checkpointDeadlineSeconds": 180, + "deadlineScope": "Checkpoint/child deadline; in-progress bounded probes and bounded reap add overhead.", + "defaultOrSearchListSetters": false, + "fixtureCreationUmask": "0077", + "binarySha256": "6a0d0d1980b505c20b5b270c8e3eceb6d0256b6b8953fbc2dad4b6f66db732cf", + "seedBinarySha256": "bc9ea0f2ee2e6bd004bb2ecb801cbc4b1cbc250b1267bf31616d1f334a102893", + "linkedLibraries": "/private/tmp/opcua2-native-import-20261110b/NativeImportControl:\n\t/System/Library/Frameworks/Security.framework/Versions/A/Security (compatibility version 1.0.0, current version 61901.101.4)\n\t/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 4424.1.255)\n\t/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1356.0.0)\n" +} diff --git a/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/result.json b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/result.json new file mode 100644 index 00000000..5aad81e7 --- /dev/null +++ b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/result.json @@ -0,0 +1,160 @@ +{ + "status": "passed", + "seed": { + "kind": "seed", + "leafSha256": "3115ab78ee0b71583ff5d7308de64af76aa2dfa33864962b170323afbba151d6", + "runtime": "10.0.14", + "sdkVersion": "2.0.1.0", + "managerDisposed": true, + "certificateCoresOutstanding": 0, + "keyFormat": "PKCS1-private-RSA", + "privateFileMode": "0600", + "cryptographyRuntime": { + "informationalVersion": "10.0.14+0427b9abbead3fa64c6655eb4290c537397131fa", + "sha256": "f4957d7218a004a27bf8964e45147df6a88092c6e7344582082840d62c6c579a" + } + }, + "samples": [ + { + "kind": "checkpoint", + "mode": "native-bridge-import", + "stage": "before", + "operations": 0, + "processId": 78495, + "utc": "2026-11-10T22:35:13.063Z", + "elapsedSeconds": 0.005821, + "rssBytes": 7749632, + "createdRefs": 0, + "releasedRefs": 0, + "managedRuntimePresent": false, + "AppleDatabaseCount": 1, + "AppleDatabaseShallowBytes": 768, + "AppleDatabaseClassAbsent": false, + "databaseManagerClassPresent": true, + "fdCount": 3, + "ownedTemporaryFdCount": 0, + "ownedKeychainFdCount": 0, + "ownedKeychainFileCount": 0 + }, + { + "kind": "checkpoint", + "mode": "native-bridge-import", + "stage": "first", + "operations": 1, + "processId": 78495, + "utc": "2026-11-10T22:35:13.932Z", + "elapsedSeconds": 0.874612, + "rssBytes": 10862592, + "createdRefs": 1, + "releasedRefs": 1, + "managedRuntimePresent": false, + "AppleDatabaseCount": 2, + "AppleDatabaseShallowBytes": 1536, + "AppleDatabaseClassAbsent": false, + "databaseManagerClassPresent": true, + "fdCount": 3, + "ownedTemporaryFdCount": 0, + "ownedKeychainFdCount": 0, + "ownedKeychainFileCount": 0 + }, + { + "kind": "checkpoint", + "mode": "native-bridge-import", + "stage": "repeated", + "operations": 200, + "processId": 78495, + "utc": "2026-11-10T22:35:23.504Z", + "elapsedSeconds": 10.446548, + "rssBytes": 14598144, + "createdRefs": 200, + "releasedRefs": 200, + "managedRuntimePresent": false, + "AppleDatabaseCount": 201, + "AppleDatabaseShallowBytes": 154368, + "AppleDatabaseClassAbsent": false, + "databaseManagerClassPresent": true, + "fdCount": 3, + "ownedTemporaryFdCount": 0, + "ownedKeychainFdCount": 0, + "ownedKeychainFileCount": 0 + }, + { + "kind": "checkpoint", + "mode": "native-bridge-import", + "stage": "idle", + "operations": 200, + "processId": 78495, + "utc": "2026-11-10T22:35:29.177Z", + "elapsedSeconds": 16.119616, + "rssBytes": 14614528, + "createdRefs": 200, + "releasedRefs": 200, + "managedRuntimePresent": false, + "AppleDatabaseCount": 201, + "AppleDatabaseShallowBytes": 154368, + "AppleDatabaseClassAbsent": false, + "databaseManagerClassPresent": true, + "fdCount": 3, + "ownedTemporaryFdCount": 0, + "ownedKeychainFdCount": 0, + "ownedKeychainFileCount": 0 + } + ], + "fingerprints": [ + { + "kind": "fingerprint", + "stage": "before", + "defaultStatus": 0, + "defaultPathStatus": 0, + "searchStatus": 0, + "searchPathStatus": 0, + "defaultSha256": "08c2c77dd8eaf8042b4020991ea06c6215cc391532869bbf6ced2cf1126c5e63", + "searchSha256": "c05fae700986dc7a6a147a938ef2adc4a274173420e137929ed58ad986eb2a3c", + "searchCount": 2, + "ownedQueryReferencesReleased": 2 + }, + { + "kind": "fingerprint", + "stage": "after", + "defaultStatus": 0, + "defaultPathStatus": 0, + "searchStatus": 0, + "searchPathStatus": 0, + "defaultSha256": "08c2c77dd8eaf8042b4020991ea06c6215cc391532869bbf6ced2cf1126c5e63", + "searchSha256": "c05fae700986dc7a6a147a938ef2adc4a274173420e137929ed58ad986eb2a3c", + "searchCount": 2, + "ownedQueryReferencesReleased": 4 + } + ], + "complete": { + "kind": "complete", + "operations": 200, + "createdRefs": 200, + "releasedRefs": 200, + "ownedOutputs": 2402, + "releasedOutputs": 2402, + "readOnlyDefaultAndSearchListUnchanged": true, + "managedRuntimePresent": false, + "bridgeSha256": "0333994e217a3d111d36d7f31460eea69a286f9fc819e2d7c746df13d2aec46c", + "elapsedSeconds": 16.772098, + "fullSoakGate": false + }, + "wallSecondsIncludingProbes": 17.022097916924395, + "fullSoakGate": false, + "nativeInventoryIsNotOpenHandlesOrExclusiveRss": true, + "measuredChildManagedRuntimePresent": false, + "actualDeletionStages": { + "release-copied-cert": 200 + }, + "returnedCopyReferencesByStage": { + "import-cert-track": 0, + "move-outer-copy": 0, + "move-cert-untrack": 0, + "move-cert-track": 200, + "move-identity-track": 0, + "identity-cert-track": 200, + "release-original-cert": 200, + "release-copied-cert": 200, + "release-identity": 0 + } +} diff --git a/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/seed-build.log b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/seed-build.log new file mode 100644 index 00000000..957054ff --- /dev/null +++ b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/seed-build.log @@ -0,0 +1,9 @@ + Determining projects to restore... + Restored /private/tmp/opcua2-native-import-20261110b/ImportSeed.csproj (in 28 ms). + ImportSeed -> /private/tmp/opcua2-native-import-20261110b/bin/Release/net10.0/ImportSeed.dll + +Build succeeded. + 0 Warning(s) + 0 Error(s) + +Time Elapsed 00:00:01.35 diff --git a/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/seed.jsonl b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/seed.jsonl new file mode 100644 index 00000000..d8775dd7 --- /dev/null +++ b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/seed.jsonl @@ -0,0 +1 @@ +{"kind":"seed","leafSha256":"3115ab78ee0b71583ff5d7308de64af76aa2dfa33864962b170323afbba151d6","runtime":"10.0.14","sdkVersion":"2.0.1.0","managerDisposed":true,"certificateCoresOutstanding":0,"keyFormat":"PKCS1-private-RSA","privateFileMode":"0600","cryptographyRuntime":{"informationalVersion":"10.0.14\u002B0427b9abbead3fa64c6655eb4290c537397131fa","sha256":"f4957d7218a004a27bf8964e45147df6a88092c6e7344582082840d62c6c579a"}} diff --git a/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/selected-samples.jsonl b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/selected-samples.jsonl new file mode 100644 index 00000000..2a17f5c4 --- /dev/null +++ b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/selected-samples.jsonl @@ -0,0 +1,9 @@ +{"kind":"fingerprint","stage":"before","defaultStatus":0,"defaultPathStatus":0,"searchStatus":0,"searchPathStatus":0,"defaultSha256":"08c2c77dd8eaf8042b4020991ea06c6215cc391532869bbf6ced2cf1126c5e63","searchSha256":"c05fae700986dc7a6a147a938ef2adc4a274173420e137929ed58ad986eb2a3c","searchCount":2,"ownedQueryReferencesReleased":2} +{"kind":"checkpoint","mode":"native-bridge-import","stage":"before","operations":0,"processId":78495,"utc":"2026-11-10T22:35:13.063Z","elapsedSeconds":0.005821,"rssBytes":7749632,"createdRefs":0,"releasedRefs":0,"managedRuntimePresent":false} +{"kind":"operation","iteration":1,"certReturn":1,"certStatus":0,"modernReturn":1,"modernErrorCode":0,"modernErrorPresent":false,"createStatus":0,"pathStatus":0,"neverLockStatus":0,"externalReturn":1,"externalErrorCode":0,"externalErrorPresent":false,"legacyReturn":1,"legacyStatus":0,"moveReturn":1,"moveStatus":0,"copyCertStatus":0,"deleteStatus":0,"privatePathVerified":true,"deleteStage":"release-copied-cert","deleteLiveReferences":{"copy":true,"originalCertificate":false,"copiedCertificate":true,"identity":true,"legacyKey":true},"importStateReleased":true,"importOwnersBefore":2,"importOwnersAfter":1,"leafIdentityChecked":true,"leafIdentityMatches":true,"fallbackCleanup":false,"logicalOwnersRemaining":0,"ownedOutputs":13,"releasedOutputs":13,"failed":false,"copies":[{"stage":"import-cert-track","action":"track","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":0,"logicalOwnersAfter":0,"nativeOwnerBefore":false,"nativeOwnerAfter":false},{"stage":"move-outer-copy","action":"lookup","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":1,"logicalOwnersAfter":1,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-cert-untrack","action":"untrack","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":1,"logicalOwnersAfter":1,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-cert-track","action":"track","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":1,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-identity-track","action":"track","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":2,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"identity-cert-track","action":"track","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":2,"logicalOwnersAfter":3,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"release-original-cert","action":"untrack","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":3,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"release-copied-cert","action":"untrack","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":1,"logicalOwnersAfter":0,"nativeOwnerBefore":true,"nativeOwnerAfter":false},{"stage":"release-identity","action":"untrack","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":0,"logicalOwnersAfter":0,"nativeOwnerBefore":false,"nativeOwnerAfter":false}]} +{"kind":"checkpoint","mode":"native-bridge-import","stage":"first","operations":1,"processId":78495,"utc":"2026-11-10T22:35:13.932Z","elapsedSeconds":0.874612,"rssBytes":10862592,"createdRefs":1,"releasedRefs":1,"managedRuntimePresent":false} +{"kind":"operation","iteration":200,"certReturn":1,"certStatus":0,"modernReturn":1,"modernErrorCode":0,"modernErrorPresent":false,"createStatus":0,"pathStatus":0,"neverLockStatus":0,"externalReturn":1,"externalErrorCode":0,"externalErrorPresent":false,"legacyReturn":1,"legacyStatus":0,"moveReturn":1,"moveStatus":0,"copyCertStatus":0,"deleteStatus":0,"privatePathVerified":true,"deleteStage":"release-copied-cert","deleteLiveReferences":{"copy":true,"originalCertificate":false,"copiedCertificate":true,"identity":true,"legacyKey":true},"importStateReleased":true,"importOwnersBefore":2,"importOwnersAfter":1,"leafIdentityChecked":true,"leafIdentityMatches":true,"fallbackCleanup":false,"logicalOwnersRemaining":0,"ownedOutputs":13,"releasedOutputs":13,"failed":false,"copies":[{"stage":"import-cert-track","action":"track","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":0,"logicalOwnersAfter":0,"nativeOwnerBefore":false,"nativeOwnerAfter":false},{"stage":"move-outer-copy","action":"lookup","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":1,"logicalOwnersAfter":1,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-cert-untrack","action":"untrack","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":1,"logicalOwnersAfter":1,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-cert-track","action":"track","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":1,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-identity-track","action":"track","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":2,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"identity-cert-track","action":"track","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":2,"logicalOwnersAfter":3,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"release-original-cert","action":"untrack","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":3,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"release-copied-cert","action":"untrack","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":1,"logicalOwnersAfter":0,"nativeOwnerBefore":true,"nativeOwnerAfter":false},{"stage":"release-identity","action":"untrack","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":0,"logicalOwnersAfter":0,"nativeOwnerBefore":false,"nativeOwnerAfter":false}]} +{"kind":"checkpoint","mode":"native-bridge-import","stage":"repeated","operations":200,"processId":78495,"utc":"2026-11-10T22:35:23.504Z","elapsedSeconds":10.446548,"rssBytes":14598144,"createdRefs":200,"releasedRefs":200,"managedRuntimePresent":false} +{"kind":"fingerprint","stage":"after","defaultStatus":0,"defaultPathStatus":0,"searchStatus":0,"searchPathStatus":0,"defaultSha256":"08c2c77dd8eaf8042b4020991ea06c6215cc391532869bbf6ced2cf1126c5e63","searchSha256":"c05fae700986dc7a6a147a938ef2adc4a274173420e137929ed58ad986eb2a3c","searchCount":2,"ownedQueryReferencesReleased":4} +{"kind":"checkpoint","mode":"native-bridge-import","stage":"idle","operations":200,"processId":78495,"utc":"2026-11-10T22:35:29.177Z","elapsedSeconds":16.119616,"rssBytes":14614528,"createdRefs":200,"releasedRefs":200,"managedRuntimePresent":false} +{"kind":"complete","operations":200,"createdRefs":200,"releasedRefs":200,"ownedOutputs":2402,"releasedOutputs":2402,"readOnlyDefaultAndSearchListUnchanged":true,"managedRuntimePresent":false,"bridgeSha256":"0333994e217a3d111d36d7f31460eea69a286f9fc819e2d7c746df13d2aec46c","elapsedSeconds":16.772098,"fullSoakGate":false} diff --git a/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/verification.json b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/verification.json new file mode 100644 index 00000000..40dc4a33 --- /dev/null +++ b/scripts/validation/opcua-lifecycle-memory/native-retention/evidence/2026-11-10-native-import-attempt-b/verification.json @@ -0,0 +1,48 @@ +{ + "status": "completed-fixed-200-positive-native-inventory", + "projection": "Replace local user-home prefix only; selected samples are exact raw row subset. Raw receipts unchanged.", + "rawOutput": "/tmp/opcua2-native-import-20261110b", + "rawSha256": { + "result.json": "73771e5aea164d0207a1096d3a9ecb92603166a82a905dfc6860598b0b37f8b1", + "provenance.json": "e58fb368c5f57051a55394fc193c5466353f202a2667d055c73745f5d9c8e0dc", + "native-build.log": "41df119d1bf1538cc52276326ff737e250ac2bbd9cdecd5ed6653e8ac473971e", + "seed-build.log": "70996c4b1c82e5356abbc5084c21598e2c3f4d5420f217acb311332a4378d61a", + "seed.jsonl": "a08c1997d04efd8288b77ca966a7b4685853202716c8a1c208a37a723a13d682", + "fixture-cleanup.json": "27288803ee9cbc51cbea3449748ad0138c6b3ae949a3a002bf6378cde9896ca8", + "fixture-before-harness-cleanup.json": "eaaf36a5e7f7d1d3635e987d8f9a2600ce55f6482011ec9a7abf3e4dd759d9c4", + "samples.jsonl": "350f35e46e159424c5e552b90e3b4a3a46d572d7ba034df274cd1646636e7498" + }, + "selectedProjectionSha256": { + "result.json": "73771e5aea164d0207a1096d3a9ecb92603166a82a905dfc6860598b0b37f8b1", + "provenance.json": "20748bd5520d4cc97b8d81fe5bef66d2670dc55863d2331a5a07e98e303ed2d5", + "native-build.log": "99cbbdd79e8a0f571fe27d412df912a45335de1b5cc8933bceb68ea7edf81681", + "seed-build.log": "70996c4b1c82e5356abbc5084c21598e2c3f4d5420f217acb311332a4378d61a", + "seed.jsonl": "a08c1997d04efd8288b77ca966a7b4685853202716c8a1c208a37a723a13d682", + "fixture-cleanup.json": "27288803ee9cbc51cbea3449748ad0138c6b3ae949a3a002bf6378cde9896ca8", + "fixture-before-harness-cleanup.json": "eaaf36a5e7f7d1d3635e987d8f9a2600ce55f6482011ec9a7abf3e4dd759d9c4", + "selected-samples.jsonl": "bfc6d3aef1e1d31174c97e8c12490a5720c5a2547a09bf8e1c6bf0d29f1438ed" + }, + "selectedSampleRawOneBasedLineNumbers": [ + 1, + 2, + 3, + 4, + 203, + 204, + 205, + 206, + 207 + ], + "rawLocalOnlySnapshotsSha256": { + "heap-before.txt": "12d73f8832ad156fc0727d8e10d1f9623f5c02e501d195a9edf5c65080d3f3c3", + "lsof-before.txt": "b07c92216960744bc485e0661af806119cb5d9350bf5ed23aae12f862032d56e", + "heap-first.txt": "0d85a6a6c63af1f4e3a906c120b551514ba6148cd92d38a4136d9fc4d6f63783", + "lsof-first.txt": "729482268e18350c8eca54094ea25a262c5cd5aa4bff300ab9260aa2fac76ae7", + "heap-repeated.txt": "4d84de1b65110b80c169be28069c972183b28dab0f82995e2f4ab017c94b412e", + "lsof-repeated.txt": "729482268e18350c8eca54094ea25a262c5cd5aa4bff300ab9260aa2fac76ae7", + "heap-idle.txt": "f5d4007db8902353aca48abb01d9a33dba3730b506ed1dbd032b014d4062527f", + "lsof-idle.txt": "729482268e18350c8eca54094ea25a262c5cd5aa4bff300ab9260aa2fac76ae7" + }, + "installedBinaryInspection": "Same pinned binaries and retained inspection hashes as attempt A verification.", + "noRetainingOwnerDefectMitigationOrFullSoakInference": true +} diff --git a/scripts/validation/opcua-lifecycle-memory/native-retention/native_import.py b/scripts/validation/opcua-lifecycle-memory/native-retention/native_import.py index 422fd228..fcb6f3bb 100644 --- a/scripts/validation/opcua-lifecycle-memory/native-retention/native_import.py +++ b/scripts/validation/opcua-lifecycle-memory/native-retention/native_import.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """One fixed-200 native bridge import diagnostic; build/run only after review.""" import argparse +from collections import Counter import hashlib import json import os @@ -92,6 +93,72 @@ def wipe_owned(root): shutil.rmtree(root) +def validate_operation(row): + if row['failed'] or row['fallbackCleanup'] or not row['privatePathVerified'] or not row['importStateReleased'] or row['logicalOwnersRemaining'] or row['modernErrorPresent'] or row['externalErrorPresent']: + raise RuntimeError('Native ownership/cleanup guard failed') + if any(row[k] for k in ['certStatus', 'createStatus', 'pathStatus', 'neverLockStatus', 'legacyStatus', 'moveStatus', 'copyCertStatus', 'deleteStatus', 'modernErrorCode', 'externalErrorCode']) or any(row[k] != 1 for k in ['certReturn', 'modernReturn', 'externalReturn', 'legacyReturn', 'moveReturn']): + raise RuntimeError('Native bridge statuses failed') + leaf_check = row['iteration'] in [1, 200] + if row['leafIdentityChecked'] != leaf_check or row['leafIdentityMatches'] != leaf_check: + raise RuntimeError('First/last native identity checks failed') + copies = row['copies'] + if [c['stage'] for c in copies] != COPY_STAGES or any(c['status'] or c['returnedRef'] != c['privateAssociation'] for c in copies): + raise RuntimeError('Native wrapper-copy sequence/status/path failed') + # Independently reconstruct ownership from observed associations, with no fixed non-null pattern. + actions = ['track', 'lookup', 'untrack', 'track', 'track', 'track', 'untrack', 'untrack', 'untrack'] + items = ['original', None, 'original', 'original', 'identity', 'copied', 'original', 'copied', 'identity'] + tracked = {'original': False, 'copied': False, 'identity': False} + logical = 0 + native_owner = False + deletion = None + live_at_delete = None + for index, (copy, action, item) in enumerate(zip(copies, actions, items)): + if index == 1: # Fresh native keychain created between DER TrackItem and Move wrapper. + logical = 1 + native_owner = True + if index == 7: # Initial import state releases after disposing the original certificate. + if row['importOwnersBefore'] != logical or not native_owner: + raise RuntimeError('Initial import owner release was misplaced') + logical -= 1 + if row['importOwnersAfter'] != logical or logical < 0: + raise RuntimeError('Initial import owner accounting failed') + if logical == 0: + deletion = 'release-import-state' + native_owner = False + live_at_delete = {'copy': False, 'originalCertificate': False, 'copiedCertificate': True, + 'identity': True, 'legacyKey': True} + if copy['action'] != action or copy['logicalOwnersBefore'] != logical or copy['nativeOwnerBefore'] != native_owner: + raise RuntimeError('Native wrapper ownership before copy does not reconcile') + associated = copy['privateAssociation'] + if action == 'track' and associated: + if tracked[item] or not native_owner: + raise RuntimeError('Track tried to duplicate or use a retired native owner') + tracked[item] = True + logical += 1 + elif action == 'untrack': + if tracked[item]: + if not associated or not native_owner: + raise RuntimeError('Previously tracked item lost its association before Untrack') + tracked[item] = False + logical -= 1 + if logical == 0: + if deletion is not None: + raise RuntimeError('Duplicate native deletion') + deletion = copy['stage'] + native_owner = False + live_at_delete = {'copy': True, 'originalCertificate': index == 6, 'copiedCertificate': index in [6, 7], + 'identity': True, 'legacyKey': True} + elif associated and native_owner: + raise RuntimeError('Untracked item would consume a still-registered owner') + if logical < 0 or copy['logicalOwnersAfter'] != logical or copy['nativeOwnerAfter'] != native_owner: + raise RuntimeError('Native wrapper ownership after copy does not reconcile') + if logical or native_owner or any(tracked.values()) or deletion is None or row['deleteStage'] != deletion or row['deleteLiveReferences'] != live_at_delete: + raise RuntimeError('Native logical owners or actual zero-owner delete stage did not reconcile') + expected_outputs = 8 + sum(c['returnedRef'] for c in copies) + int(leaf_check) + if row['ownedOutputs'] != expected_outputs or row['releasedOutputs'] != expected_outputs: + raise RuntimeError('Native returned CF ownership did not reconcile') + + def main(): os.umask(0o077) # This collector and its children only; includes normal SDK seed PFX files. parser = argparse.ArgumentParser(description=__doc__) @@ -117,7 +184,7 @@ def main(): 'repetitions': 200, 'stages': STAGES, 'idleSeconds': 5, 'fullSoakGate': False, 'managedCallerInMeasuredChild': False, 'managedPfxParsingEmulated': False, 'legacyKeyLifetime': 'Explicit CFRelease after identity disposal; managed local has no explicit using scope.', - 'wrapperNativeCopyCallsPerOperation': 9, 'checkpointDeadlineSeconds': 180, + 'wrapperNativeCopyCallsPerOperation': 9, 'logicalOwnersFromObservedPrivateAssociationsOnly': True, 'checkpointDeadlineSeconds': 180, 'deadlineScope': 'Checkpoint/child deadline; in-progress bounded probes and bounded reap add overhead.', 'defaultOrSearchListSetters': False, 'fixtureCreationUmask': '0077'} save(output / 'provenance.json', provenance) @@ -180,19 +247,16 @@ def main(): if status or len(rows) != 207 or len(operations) != 200 or len(fingerprints) != 2 or len(complete) != 1 or [r['iteration'] for r in operations] != list(range(1, 201)): raise RuntimeError('Native fixed operation/completion counts failed') for row in operations: - if row['failed'] or row['fallbackCleanup'] or not row['privatePathVerified'] or not row['deleteDuringFinalIdentityUntrack'] or row['logicalOwnersRemaining'] or row['modernErrorPresent'] or row['externalErrorPresent'] or row['ownedOutputs'] != row['releasedOutputs']: - raise RuntimeError('Native ownership order/cleanup failed') - if [c['stage'] for c in row['copies']] != COPY_STAGES or any(c['status'] for c in row['copies']) or [c['returnedRef'] for c in row['copies']] != [False] * 3 + [True] * 6: - raise RuntimeError('Native wrapper-copy sequence failed') - if any(row[k] for k in ['certStatus', 'createStatus', 'pathStatus', 'neverLockStatus', 'legacyStatus', 'moveStatus', 'copyCertStatus', 'deleteStatus', 'modernErrorCode', 'externalErrorCode']) or any(row[k] != 1 for k in ['certReturn', 'modernReturn', 'externalReturn', 'legacyReturn', 'moveReturn']): - raise RuntimeError('Native bridge statuses failed') - if sha(task / 'seed/leaf.der') != seeds[0]['leafSha256'] or complete[0]['operations'] != 200 or complete[0]['bridgeSha256'] != BRIDGE_SHA or complete[0]['ownedOutputs'] != complete[0]['releasedOutputs']: + validate_operation(row) + if sha(task / 'seed/leaf.der') != seeds[0]['leafSha256'] or complete[0]['operations'] != 200 or complete[0]['bridgeSha256'] != BRIDGE_SHA or complete[0]['ownedOutputs'] != sum(r['ownedOutputs'] for r in operations) or complete[0]['releasedOutputs'] != sum(r['releasedOutputs'] for r in operations) or complete[0]['createdRefs'] != 200 or complete[0]['releasedRefs'] != 200: raise RuntimeError('Native identity/completion ownership guard failed') if any(samples[-1][k] for k in ['ownedKeychainFdCount', 'ownedKeychainFileCount']): raise RuntimeError('Private keychain files/descriptors retained') save(output / 'result.json', {'status': 'passed', 'seed': seeds[0], 'samples': samples, 'fingerprints': fingerprints, 'complete': complete[0], 'wallSecondsIncludingProbes': time.monotonic() - started, 'fullSoakGate': False, - 'nativeInventoryIsNotOpenHandlesOrExclusiveRss': True, 'measuredChildManagedRuntimePresent': False}) + 'nativeInventoryIsNotOpenHandlesOrExclusiveRss': True, 'measuredChildManagedRuntimePresent': False, + 'actualDeletionStages': dict(Counter(r['deleteStage'] for r in operations)), + 'returnedCopyReferencesByStage': {stage: sum(c['returnedRef'] for r in operations for c in r['copies'] if c['stage'] == stage) for stage in COPY_STAGES}}) finally: reap(process) finally: