From 392b3636ee417170800c4b8987b0b09626aa695b Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 25 Sep 2026 16:36:29 +0700 Subject: [PATCH 1/9] docs(provenance): add per-file tracked asset manifest --- docs/asset-provenance-manifest.json | 481 ++++++++++++++++++++++++++++ 1 file changed, 481 insertions(+) create mode 100644 docs/asset-provenance-manifest.json diff --git a/docs/asset-provenance-manifest.json b/docs/asset-provenance-manifest.json new file mode 100644 index 000000000..cdc9c83f5 --- /dev/null +++ b/docs/asset-provenance-manifest.json @@ -0,0 +1,481 @@ +{ + "schema_version": 1, + "audited_repository": "masarray/arsas", + "audited_commit": "61ad333c2f61784ee49fda04b47f036206265cbc", + "audited_date": "2026-09-25", + "scope": "Git-tracked binary visual/font assets with extensions png,jpg,jpeg,webp,ico,svg,ttf,otf,woff2,gif", + "disclaimer": "Inventory and Git identity only. This manifest does not certify originality, license clearance, or freedom from resemblance. Manual origin/rights/content review remains required where disposition says so.", + "tracked_asset_count": 67, + "unique_blob_count": 44, + "files": [ + { + "path": "Assets/Fonts/Inter-Bold.ttf", + "blob_sha": "9fb9b751e5b2441054f6eef670da7b3f53a3505a", + "size_bytes": 420428, + "duplicate_of": null, + "review_status": "third-party-font-notice-present; exact-upstream-package-review-required" + }, + { + "path": "Assets/Fonts/Inter-Medium.ttf", + "blob_sha": "458cd0601d28013d3817481aa2839c9bbb5ded70", + "size_bytes": 417300, + "duplicate_of": null, + "review_status": "third-party-font-notice-present; exact-upstream-package-review-required" + }, + { + "path": "Assets/Fonts/Inter-Regular.ttf", + "blob_sha": "b7aaca8de1fe458399e17311d35d543a1fa2f984", + "size_bytes": 411640, + "duplicate_of": null, + "review_status": "third-party-font-notice-present; exact-upstream-package-review-required" + }, + { + "path": "Assets/Fonts/Inter-SemiBold.ttf", + "blob_sha": "47f8ab1d68144fc004b310d65d95180d502b449b", + "size_bytes": 419744, + "duplicate_of": null, + "review_status": "third-party-font-notice-present; exact-upstream-package-review-required" + }, + { + "path": "Assets/RelayFascia.svg", + "blob_sha": "9a69c173b9efdbf8f622f630e4cbeb1f5318699a", + "size_bytes": 11506, + "duplicate_of": null, + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "Assets/app-icon-256.png", + "blob_sha": "fd8f941baa44811e97be408663c7e54b57ad85a1", + "size_bytes": 12891, + "duplicate_of": null, + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "Assets/app-icon.ico", + "blob_sha": "cc9036ccfb9b387891d9887b4367262b7d154bca", + "size_bytes": 208630, + "duplicate_of": null, + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "Assets/app-icon.png", + "blob_sha": "7b69ac247a7214d15437a69814f4036cedebc86e", + "size_bytes": 153165, + "duplicate_of": null, + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "Assets/black-fascia-ied.svg", + "blob_sha": "0c4594a762fe5f13df6ff7b005def3bc7b5cffd7", + "size_bytes": 14334, + "duplicate_of": null, + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "Assets/gateway-hero.png", + "blob_sha": "cb1141207830159642a8f73f981bccbce94e840e", + "size_bytes": 1658537, + "duplicate_of": null, + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "Assets/ied-protection-relay-fascia.png", + "blob_sha": "8d47aee5707eadd373489bc7670da9d99aa24238", + "size_bytes": 1131989, + "duplicate_of": null, + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "Assets/screenshot/arsas (1).webp", + "blob_sha": "4ff8ea73132e1616e585f7020068dfcae29dcf77", + "size_bytes": 116714, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas (2).webp", + "blob_sha": "275e7b3e64478c48a517b0665a3642cc78da4e37", + "size_bytes": 134920, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas (3).webp", + "blob_sha": "8a873301cd7b7dfc1eb2502bf1f4371bc0d7e897", + "size_bytes": 126090, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas (4).webp", + "blob_sha": "3f242ce2c1dd945395cf70c54d92e0eedeaf9fbe", + "size_bytes": 140392, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas (5).webp", + "blob_sha": "dde93be42222734bbccb9f724119e12dcc08b7df", + "size_bytes": 138672, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas (6).webp", + "blob_sha": "5bed62792b9c383b99886df2024524b6d5d69db5", + "size_bytes": 142298, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-alarm-annunciator-v1.6.40.webp", + "blob_sha": "29b9b3866ce8b29b401df8ffde0cd9239b623b5d", + "size_bytes": 133632, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-comtrade-harmonics-v1.6.40.webp", + "blob_sha": "7d8484b8ed7e613ff283ad6fdcfdadb04a56d977", + "size_bytes": 85884, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-comtrade-locus-v1.6.40.webp", + "blob_sha": "b1a6bcb05222d491164b42fb8710d227e9de4e17", + "size_bytes": 64714, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-comtrade-phasor-v1.6.40.webp", + "blob_sha": "b820739847f984aff27d656387084efa2a90b53b", + "size_bytes": 77708, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-comtrade-protection-timeline-v1.6.40.webp", + "blob_sha": "5a5c5aef148d5bb4bb0fae4d04ab742b93e4f036", + "size_bytes": 75964, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-comtrade-time-signals-v1.6.40.webp", + "blob_sha": "d9f4f7c4b7eeb1b18b059772592032ac4342021f", + "size_bytes": 87612, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-fat-report-preview-v1.6.40.webp", + "blob_sha": "5d2a566f4b2854a8469ec2fd4821d86fe5438c54", + "size_bytes": 49254, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-fault-records-v1.6.40.webp", + "blob_sha": "882b626dbc260b2846f946257c32a1aeea8c288f", + "size_bytes": 55328, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-ied-explorer-command-v1.6.40.webp", + "blob_sha": "3f1878f290454f278ab97a56f5683a8efbbb0a4d", + "size_bytes": 137946, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-landing-home-desktop-v1.6.19.png", + "blob_sha": "1c7c76eb8df9de60c5be0fe84977a9ea926d0e3b", + "size_bytes": 104657, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-landing-home-mobile-v1.6.19.png", + "blob_sha": "9fefd8a0503fbe17abbb7bcba2b0c013ddd48b8a", + "size_bytes": 38921, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-native-fat-v1.6.40.webp", + "blob_sha": "f7e47cfe02decd87cb9e53d699611b2d421963dd", + "size_bytes": 166496, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-overview-v1.6.19.webp", + "blob_sha": "ec0ba89c4f03dc6b29129b92f8032b54cb9be2b9", + "size_bytes": 111848, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-quick-start-choose-source-v1.6.40.webp", + "blob_sha": "303fbb149a639a3c14511cbe259017788fe51f5a", + "size_bytes": 136494, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-quick-start-discover-ip-v1.6.40.webp", + "blob_sha": "f63829ff8f49f3badee38dd20431d24671496325", + "size_bytes": 134446, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-quick-start-monitor-control-v1.6.40.webp", + "blob_sha": "b977d8bb592522678778d146f27b8c12424c260d", + "size_bytes": 98562, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-rcb-selection-v1.6.40.webp", + "blob_sha": "b1179f8acbc924c95f94d4d7b0c963fdd5db129d", + "size_bytes": 36876, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-scl-edition-export-v1.6.40.webp", + "blob_sha": "a23c3576823e719a85e8f94e398a82e57fe40755", + "size_bytes": 29244, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/screenshot/arsas-sequence-of-events-v1.6.40.webp", + "blob_sha": "0bb53fa0f39320c57e6e3a812fbe0574b2fe18d9", + "size_bytes": 150598, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "Assets/social/arsas-og-industrial-background.webp", + "blob_sha": "9af8f6e4919fda46bc5ab1496eb6b30c86943335", + "size_bytes": 62230, + "duplicate_of": null, + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "landing/assets/arsas-substation-context.webp", + "blob_sha": "9af8f6e4919fda46bc5ab1496eb6b30c86943335", + "size_bytes": 62230, + "duplicate_of": "Assets/social/arsas-og-industrial-background.webp", + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "landing/assets/favicon.svg", + "blob_sha": "836e0b588a09245f969e6f2e9b9996d433d309f8", + "size_bytes": 547, + "duplicate_of": null, + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-alarm-annunciator-v1.6.40.webp", + "blob_sha": "29b9b3866ce8b29b401df8ffde0cd9239b623b5d", + "size_bytes": 133632, + "duplicate_of": "Assets/screenshot/arsas-alarm-annunciator-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-comtrade-harmonics-v1.6.40.webp", + "blob_sha": "7d8484b8ed7e613ff283ad6fdcfdadb04a56d977", + "size_bytes": 85884, + "duplicate_of": "Assets/screenshot/arsas-comtrade-harmonics-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-comtrade-locus-v1.6.40.webp", + "blob_sha": "b1a6bcb05222d491164b42fb8710d227e9de4e17", + "size_bytes": 64714, + "duplicate_of": "Assets/screenshot/arsas-comtrade-locus-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-comtrade-phasor-v1.6.40.webp", + "blob_sha": "b820739847f984aff27d656387084efa2a90b53b", + "size_bytes": 77708, + "duplicate_of": "Assets/screenshot/arsas-comtrade-phasor-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-comtrade-protection-timeline-v1.6.40.webp", + "blob_sha": "5a5c5aef148d5bb4bb0fae4d04ab742b93e4f036", + "size_bytes": 75964, + "duplicate_of": "Assets/screenshot/arsas-comtrade-protection-timeline-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-comtrade-time-signals-v1.6.40.webp", + "blob_sha": "d9f4f7c4b7eeb1b18b059772592032ac4342021f", + "size_bytes": 87612, + "duplicate_of": "Assets/screenshot/arsas-comtrade-time-signals-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-diagnostics.webp", + "blob_sha": "5bed62792b9c383b99886df2024524b6d5d69db5", + "size_bytes": 142298, + "duplicate_of": "Assets/screenshot/arsas (6).webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-event-log.webp", + "blob_sha": "3f242ce2c1dd945395cf70c54d92e0eedeaf9fbe", + "size_bytes": 140392, + "duplicate_of": "Assets/screenshot/arsas (4).webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-fat-report-preview-v1.6.40.webp", + "blob_sha": "5d2a566f4b2854a8469ec2fd4821d86fe5438c54", + "size_bytes": 49254, + "duplicate_of": "Assets/screenshot/arsas-fat-report-preview-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-fault-records-v1.6.40.webp", + "blob_sha": "882b626dbc260b2846f946257c32a1aeea8c288f", + "size_bytes": 55328, + "duplicate_of": "Assets/screenshot/arsas-fault-records-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-first-launch.webp", + "blob_sha": "8a873301cd7b7dfc1eb2502bf1f4371bc0d7e897", + "size_bytes": 126090, + "duplicate_of": "Assets/screenshot/arsas (3).webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-goose.webp", + "blob_sha": "dde93be42222734bbccb9f724119e12dcc08b7df", + "size_bytes": 138672, + "duplicate_of": "Assets/screenshot/arsas (5).webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-ied-explorer-command-v1.6.40.webp", + "blob_sha": "3f1878f290454f278ab97a56f5683a8efbbb0a4d", + "size_bytes": 137946, + "duplicate_of": "Assets/screenshot/arsas-ied-explorer-command-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-live-values.webp", + "blob_sha": "275e7b3e64478c48a517b0665a3642cc78da4e37", + "size_bytes": 134920, + "duplicate_of": "Assets/screenshot/arsas (2).webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-multi-ied.webp", + "blob_sha": "4ff8ea73132e1616e585f7020068dfcae29dcf77", + "size_bytes": 116714, + "duplicate_of": "Assets/screenshot/arsas (1).webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-native-fat-v1.6.40.webp", + "blob_sha": "f7e47cfe02decd87cb9e53d699611b2d421963dd", + "size_bytes": 166496, + "duplicate_of": "Assets/screenshot/arsas-native-fat-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-overview-v1.6.19.webp", + "blob_sha": "dfebe207b911f47e688da65893a83c5cb4105905", + "size_bytes": 101468, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-quick-start-choose-source-v1.6.40.webp", + "blob_sha": "303fbb149a639a3c14511cbe259017788fe51f5a", + "size_bytes": 136494, + "duplicate_of": "Assets/screenshot/arsas-quick-start-choose-source-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-quick-start-discover-ip-v1.6.40.webp", + "blob_sha": "f63829ff8f49f3badee38dd20431d24671496325", + "size_bytes": 134446, + "duplicate_of": "Assets/screenshot/arsas-quick-start-discover-ip-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-quick-start-monitor-control-v1.6.40.webp", + "blob_sha": "b977d8bb592522678778d146f27b8c12424c260d", + "size_bytes": 98562, + "duplicate_of": "Assets/screenshot/arsas-quick-start-monitor-control-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-rcb-scl-export.webp", + "blob_sha": "33625676e8f2adcb3d0c93f56a6b2760a430de4d", + "size_bytes": 130058, + "duplicate_of": null, + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-rcb-selection-v1.6.40.webp", + "blob_sha": "b1179f8acbc924c95f94d4d7b0c963fdd5db129d", + "size_bytes": 36876, + "duplicate_of": "Assets/screenshot/arsas-rcb-selection-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-scl-edition-export-v1.6.40.webp", + "blob_sha": "a23c3576823e719a85e8f94e398a82e57fe40755", + "size_bytes": 29244, + "duplicate_of": "Assets/screenshot/arsas-scl-edition-export-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/screenshots/arsas-sequence-of-events-v1.6.40.webp", + "blob_sha": "0bb53fa0f39320c57e6e3a812fbe0574b2fe18d9", + "size_bytes": 150598, + "duplicate_of": "Assets/screenshot/arsas-sequence-of-events-v1.6.40.webp", + "review_status": "capture-origin-and-sanitization-review-required" + }, + { + "path": "landing/assets/social-card.png", + "blob_sha": "8708a22b5c0c8f96a9825ad6b39be249e9ddd075", + "size_bytes": 389388, + "duplicate_of": null, + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "landing/assets/social-card.svg", + "blob_sha": "11fc6b3b24db27ab5c231a31920763761cf3bb29", + "size_bytes": 3181, + "duplicate_of": null, + "review_status": "origin-rights-and-visual-similarity-review-required" + }, + { + "path": "output/scl-signal-selection-comparison.png", + "blob_sha": "c3a6ff981b40eb6878da5349fe80d1fbe9eab09f", + "size_bytes": 598548, + "duplicate_of": null, + "review_status": "legacy-output-origin-and-visual-similarity-review-required" + }, + { + "path": "output/scl-signal-selection-modern.png", + "blob_sha": "4f0acfe082833972f84de58c74280ad86991cbd3", + "size_bytes": 65657, + "duplicate_of": null, + "review_status": "legacy-output-origin-and-visual-similarity-review-required" + } + ] +} From b3e07d4105a0a392af22ff640e589953d62bccc8 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 25 Sep 2026 16:37:37 +0700 Subject: [PATCH 2/9] docs(provenance): link per-file asset inventory and CI contract --- docs/ASSET_PROVENANCE_REGISTER.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/ASSET_PROVENANCE_REGISTER.md b/docs/ASSET_PROVENANCE_REGISTER.md index 8ed09f5f8..1cbe3d636 100644 --- a/docs/ASSET_PROVENANCE_REGISTER.md +++ b/docs/ASSET_PROVENANCE_REGISTER.md @@ -6,10 +6,12 @@ This register supports the [independent implementation and provenance policy](IN ## Audited snapshot -- Repository: `masarray/arsas`; tracked recursive Git tree at `d656aa4faf141ede084f2063bca3c091ca1021e5` (2026-09-25). -- Full recursive tree response: not truncated; 1,026 tracked blobs. +- Repository: `masarray/arsas`; tracked recursive Git tree at `61ad333c2f61784ee49fda04b47f036206265cbc` (2026-09-25). +- Full recursive tree response: not truncated; 1,028 tracked blobs. - Extension inventory: 67 `.png`, `.jpg`/`.jpeg`, `.webp`, `.ico`, `.svg`, `.ttf`, `.otf`, `.woff2` or `.gif` blobs. - This is a *path and Git-blob metadata inventory*, not an image-content, source-license, hidden-metadata, or legal review. The separately maintained source-clean gate scans tracked paths and supported text contents; it does not establish binary-image provenance. +- The machine-readable [per-file asset manifest](asset-provenance-manifest.json) records all 67 tracked asset paths, their Git blob SHA, byte size, exact-duplicate relationship and explicit review status. There are 44 unique asset blobs; 23 duplicate groups are byte-for-byte deployments of the same Git blob at two paths. +- CI validates that every tracked asset in this extension scope is represented and that its blob SHA still matches the manifest. Changing or adding an asset therefore requires an explicit provenance-manifest update rather than silently entering the tree. | Category | Count | Scope | Origin/rights disposition | | --- | ---: | --- | --- | From d512affce81428185cde0cff4d15f7a414685942 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 25 Sep 2026 16:38:06 +0700 Subject: [PATCH 3/9] ci(provenance): verify every tracked asset against manifest --- scripts/verify-asset-provenance-manifest.ps1 | 92 ++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 scripts/verify-asset-provenance-manifest.ps1 diff --git a/scripts/verify-asset-provenance-manifest.ps1 b/scripts/verify-asset-provenance-manifest.ps1 new file mode 100644 index 000000000..e1b232593 --- /dev/null +++ b/scripts/verify-asset-provenance-manifest.ps1 @@ -0,0 +1,92 @@ +param( + [string]$RepositoryRoot = (Split-Path -Parent $PSScriptRoot) +) + +$ErrorActionPreference = "Stop" +$RepoRoot = (Resolve-Path -LiteralPath $RepositoryRoot).Path +$ManifestPath = Join-Path $RepoRoot "docs\asset-provenance-manifest.json" + +if (-not (Test-Path -LiteralPath $ManifestPath -PathType Leaf)) { + throw "Asset provenance manifest was not found: $ManifestPath" +} + +$manifest = Get-Content -LiteralPath $ManifestPath -Raw | ConvertFrom-Json +if ($manifest.schema_version -ne 1) { + throw "Unsupported asset provenance manifest schema version: $($manifest.schema_version)" +} + +$extensions = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) +@(".png", ".jpg", ".jpeg", ".webp", ".ico", ".svg", ".ttf", ".otf", ".woff2", ".gif") | + ForEach-Object { [void]$extensions.Add($_) } + +$trackedAssets = @( + & git -C $RepoRoot ls-files | + ForEach-Object { $_.Replace("\", "/") } | + Where-Object { $extensions.Contains([IO.Path]::GetExtension($_)) } | + Sort-Object +) + +if ($LASTEXITCODE -ne 0) { + throw "git ls-files failed while validating asset provenance." +} + +$manifestFiles = @($manifest.files) +if ($manifestFiles.Count -ne $trackedAssets.Count) { + throw "Asset provenance manifest count mismatch. Manifest=$($manifestFiles.Count), tracked=$($trackedAssets.Count)." +} + +$byPath = [System.Collections.Generic.Dictionary[string,object]]::new([System.StringComparer]::Ordinal) +foreach ($entry in $manifestFiles) { + $path = [string]$entry.path + if ([string]::IsNullOrWhiteSpace($path)) { + throw "Asset provenance manifest contains an entry without a path." + } + if ($byPath.ContainsKey($path)) { + throw "Asset provenance manifest contains duplicate path: $path" + } + if ([string]::IsNullOrWhiteSpace([string]$entry.review_status)) { + throw "Asset provenance manifest entry has no review status: $path" + } + $byPath.Add($path, $entry) +} + +foreach ($relative in $trackedAssets) { + if (-not $byPath.ContainsKey($relative)) { + throw "Tracked asset is missing from provenance manifest: $relative" + } + + $entry = $byPath[$relative] + $actualSha = (& git -C $RepoRoot hash-object -- $relative).Trim() + if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($actualSha)) { + throw "Unable to calculate Git blob SHA for tracked asset: $relative" + } + if (-not $actualSha.Equals([string]$entry.blob_sha, [StringComparison]::OrdinalIgnoreCase)) { + throw "Asset provenance blob mismatch for $relative. Manifest=$($entry.blob_sha), actual=$actualSha" + } + + $fullPath = Join-Path $RepoRoot ($relative.Replace("/", [IO.Path]::DirectorySeparatorChar)) + $actualSize = (Get-Item -LiteralPath $fullPath).Length + if ([long]$entry.size_bytes -ne $actualSize) { + throw "Asset provenance size mismatch for $relative. Manifest=$($entry.size_bytes), actual=$actualSize" + } + + $duplicateOf = [string]$entry.duplicate_of + if (-not [string]::IsNullOrWhiteSpace($duplicateOf)) { + if (-not $byPath.ContainsKey($duplicateOf)) { + throw "Asset provenance duplicate_of target does not exist: $relative -> $duplicateOf" + } + if (-not ([string]$byPath[$duplicateOf].blob_sha).Equals([string]$entry.blob_sha, [StringComparison]::OrdinalIgnoreCase)) { + throw "Asset provenance duplicate_of target has a different blob: $relative -> $duplicateOf" + } + } +} + +$uniqueBlobCount = @($manifestFiles | ForEach-Object { [string]$_.blob_sha } | Sort-Object -Unique).Count +if ([int]$manifest.tracked_asset_count -ne $trackedAssets.Count) { + throw "tracked_asset_count does not match manifest entries." +} +if ([int]$manifest.unique_blob_count -ne $uniqueBlobCount) { + throw "unique_blob_count does not match manifest entries." +} + +Write-Host "Asset provenance manifest PASS: $($trackedAssets.Count) tracked paths, $uniqueBlobCount unique Git blobs." -ForegroundColor Green From 51022eabdf8263360cd24135c3256b2369352c83 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 25 Sep 2026 16:38:23 +0700 Subject: [PATCH 4/9] ci(provenance): gate asset changes on reviewed manifest --- scripts/verify-source-clean.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/verify-source-clean.ps1 b/scripts/verify-source-clean.ps1 index ace318e6b..8b47348cc 100644 --- a/scripts/verify-source-clean.ps1 +++ b/scripts/verify-source-clean.ps1 @@ -201,6 +201,7 @@ if ($Problems.Count -gt 0) { } if (-not $ScanOnly) { + & (Join-Path $PSScriptRoot "verify-asset-provenance-manifest.ps1") -RepositoryRoot $RepoRoot & (Join-Path $PSScriptRoot "verify-fault-record-bindings.ps1") & (Join-Path $PSScriptRoot "verify-auto-update.ps1") } From b7eedf501cb88a7f6f0960562a279a0007e311a9 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 25 Sep 2026 16:41:41 +0700 Subject: [PATCH 5/9] fix(provenance): validate asset size from Git blob, not checkout bytes --- scripts/verify-asset-provenance-manifest.ps1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/verify-asset-provenance-manifest.ps1 b/scripts/verify-asset-provenance-manifest.ps1 index e1b232593..d1d721623 100644 --- a/scripts/verify-asset-provenance-manifest.ps1 +++ b/scripts/verify-asset-provenance-manifest.ps1 @@ -64,10 +64,13 @@ foreach ($relative in $trackedAssets) { throw "Asset provenance blob mismatch for $relative. Manifest=$($entry.blob_sha), actual=$actualSha" } - $fullPath = Join-Path $RepoRoot ($relative.Replace("/", [IO.Path]::DirectorySeparatorChar)) - $actualSize = (Get-Item -LiteralPath $fullPath).Length + $actualSizeText = (& git -C $RepoRoot cat-file -s $actualSha).Trim() + if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($actualSizeText)) { + throw "Unable to read Git blob size for tracked asset: $relative" + } + $actualSize = [long]$actualSizeText if ([long]$entry.size_bytes -ne $actualSize) { - throw "Asset provenance size mismatch for $relative. Manifest=$($entry.size_bytes), actual=$actualSize" + throw "Asset provenance size mismatch for $relative. Manifest=$($entry.size_bytes), GitBlob=$actualSize" } $duplicateOf = [string]$entry.duplicate_of From 94f4894f87f60f48702106271f5564d68b5472e9 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 25 Sep 2026 16:43:53 +0700 Subject: [PATCH 6/9] docs(provenance): replace unverified absolute IP claim with enforceable policy --- THIRD_PARTY_NOTICES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 7f065c87b..652f414ff 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -17,10 +17,12 @@ The bundled font files are redistributed unmodified. ARSAS does not rename the I ## External intellectual-property boundary -No source code, binary, header, generated binding, wrapper, example, test, API layer, executable, manual, brochure, help file, screenshot, icon, logo, product photo, report template, UI resource, database, capture, or extracted asset from an unrelated external implementation or proprietary engineering product is included or directly required by this application repository. +Project policy prohibits including source code, binary, header, generated binding, wrapper, example, test, API layer, executable, manual, brochure, help file, screenshot, icon, logo, product photo, report template, UI resource, database, capture, or extracted asset copied from an unrelated external implementation or proprietary engineering product. Interoperability testing with separately licensed tools does not make those tools application dependencies and does not authorize copying their software, documentation, visual design, reports, resources, or confidential data. +Tracked visual and font assets are inventoried in [docs/ASSET_PROVENANCE_REGISTER.md](docs/ASSET_PROVENANCE_REGISTER.md) and its machine-readable manifest. An inventory entry or passing source-clean check is not a certification of authorship, license clearance, or visual independence; unresolved origin/rights review remains explicitly recorded there. + ## Assets and releases All application icons, screenshots, illustrations, UI resources, and marketing images included in a release must be project-owned or separately licensed for that use. Screenshots must be generated from ARSAS itself using synthetic or sanitized data. From 99b3fa10053c02675c85f16b9e78701a1fade83d Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 25 Sep 2026 16:44:57 +0700 Subject: [PATCH 7/9] fix(source-clean): scan extensionless repository policy files --- scripts/verify-source-clean.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/verify-source-clean.ps1 b/scripts/verify-source-clean.ps1 index 8b47348cc..4c9ab0a8f 100644 --- a/scripts/verify-source-clean.ps1 +++ b/scripts/verify-source-clean.ps1 @@ -60,6 +60,10 @@ $TextExtensions = @( ".props", ".targets", ".sln", ".slnx", ".txt" ) +$TextFileNames = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) +@(".editorconfig", ".gitattributes", ".gitignore", "CODEOWNERS", "LICENSE", "NOTICE", "VERSION") | + ForEach-Object { [void]$TextFileNames.Add($_) } + # No tracked path receives a whole-file external-identifier exemption. Historical # comparison evidence is linked by immutable commit rather than copied into active files. $Problems = New-Object System.Collections.Generic.List[string] @@ -179,7 +183,9 @@ foreach ($relative in (Get-TrackedRelativePaths)) { } if ($relative -eq "scripts/verify-source-clean.ps1") { continue } - if ($TextExtensions -notcontains [IO.Path]::GetExtension($relative).ToLowerInvariant()) { continue } + $extension = [IO.Path]::GetExtension($relative).ToLowerInvariant() + $leafName = [IO.Path]::GetFileName($relative) + if ($TextExtensions -notcontains $extension -and -not $TextFileNames.Contains($leafName)) { continue } $content = Get-Content -LiteralPath $fullPath -Raw -ErrorAction SilentlyContinue if (Test-ContainsForbiddenIdentifier $content) { From 9ffcea40c217187a09e4d9e90076d4504e368158 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 25 Sep 2026 16:45:15 +0700 Subject: [PATCH 8/9] test(source-clean): reject identifiers in extensionless and dotfile text --- scripts/test-source-clean-guard.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/test-source-clean-guard.ps1 b/scripts/test-source-clean-guard.ps1 index 9b7448b31..345bbdc5e 100644 --- a/scripts/test-source-clean-guard.ps1 +++ b/scripts/test-source-clean-guard.ps1 @@ -16,6 +16,8 @@ $cases = @( @{ Path = "docs/reference.md"; Text = "# $identifier"; Expected = "text" }, @{ Path = "evidence/fixture.json"; Text = "{`"reference`": `"$identifier`"}"; Expected = "text" }, @{ Path = ".github/workflows/smart-discovery-post-merge-production.yml"; Text = "name: $identifier"; Expected = "text" }, + @{ Path = "NOTICE"; Text = "Policy marker: $identifier"; Expected = "text" }, + @{ Path = ".gitignore"; Text = "# $identifier"; Expected = "text" }, @{ Path = "tests/ARSAS.Tests/SyntheticFixture.cs"; Text = "// $identifier"; Expected = "text" }, @{ Path = "docs/${identifier}-fixture.md"; Text = "# independently generated fixture"; Expected = "path" }, @{ Path = "docs/split-name.md"; Text = $identifier.Substring(0, 3) + " " + $identifier.Substring(3); Expected = "text" }, From 7c8a0c97e034965bf1a984b26c349dedcea9a395 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 25 Sep 2026 16:46:54 +0700 Subject: [PATCH 9/9] fix(source-clean): distinguish ignore policy from leaked build-path text --- scripts/verify-source-clean.ps1 | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/verify-source-clean.ps1 b/scripts/verify-source-clean.ps1 index 4c9ab0a8f..db4d9cb8b 100644 --- a/scripts/verify-source-clean.ps1 +++ b/scripts/verify-source-clean.ps1 @@ -64,6 +64,9 @@ $TextFileNames = [System.Collections.Generic.HashSet[string]]::new([System.Strin @(".editorconfig", ".gitattributes", ".gitignore", "CODEOWNERS", "LICENSE", "NOTICE", "VERSION") | ForEach-Object { [void]$TextFileNames.Add($_) } +$InternalPatternPolicyFiles = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) +@(".gitignore") | ForEach-Object { [void]$InternalPatternPolicyFiles.Add($_) } + # No tracked path receives a whole-file external-identifier exemption. Historical # comparison evidence is linked by immutable commit rather than copied into active files. $Problems = New-Object System.Collections.Generic.List[string] @@ -192,9 +195,11 @@ foreach ($relative in (Get-TrackedRelativePaths)) { $Problems.Add("Forbidden external identifier in text: $relative") } - foreach ($pattern in $ForbiddenTextPatterns) { - if ($content -match [regex]::Escape($pattern)) { - $Problems.Add("Forbidden internal-release text: $relative") + if (-not $InternalPatternPolicyFiles.Contains($leafName)) { + foreach ($pattern in $ForbiddenTextPatterns) { + if ($content -match [regex]::Escape($pattern)) { + $Problems.Add("Forbidden internal-release text: $relative") + } } } }