SBOM Preservation Receipt avatar

SBOM Preservation Receipt

Pricing

$0.05 / useful sbom preservation receipt

Go to Apify Store
SBOM Preservation Receipt

SBOM Preservation Receipt

Experimental comparison of an SPDX 2.3 original and CycloneDX 1.6 conversion: supported facts, direct edges, changes and uncertainty. No conversion or acceptance certification.

Pricing

$0.05 / useful sbom preservation receipt

Rating

0.0

(0)

Developer

L3Digital

L3Digital

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

17 days ago

Last modified

Categories

Share

Identify covered declarations that changed or disappeared during an SPDX 2.3 to CycloneDX 1.6 conversion. Supply the original and already-converted JSON artifacts; the receipt compares covered facts and dependency edges, localizes differences and unresolved correspondence, and gives a supplier-intake agent repairs or questions to review before handoff.

This experimental Actor requires the caller to acquire both artifacts. It does not convert or fetch files, scan vulnerabilities, log into a recipient system, or import an SBOM.

Input

Supply original and converted as inline JSON objects. The following is a minimal structural example, not a complete standards-valid SBOM:

{
"original": {
"spdxVersion": "SPDX-2.3",
"packages": [
{
"SPDXID": "SPDXRef-alpha",
"name": "alpha",
"versionInfo": "1.0",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:generic/alpha@1.0"
}
]
}
]
},
"converted": {
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"components": [
{
"bom-ref": "alpha",
"name": "alpha",
"version": "1.0",
"purl": "pkg:generic/alpha@1.0"
}
]
}
}

Under the contract, this pair matches by its unique exact PURL and compares three declared facts. SHA256 is not_declared; its absence is not preservation. There are no declared dependency edges in this example.

Eligible records have a unique nonempty source SPDXID or target bom-ref. Automatic correspondence requires eligible IDs and one exact PURL occurring once on each side. Source references must use exactly PACKAGE-MANAGER and purl. No name/version, CPE, substring or normalized-PURL fallback is used. A target metadata.component is included alongside top-level components.

When a PURL changes or is absent, you may add an explicit correspondence assertion:

"mapping": [{"sourceId": "SPDXRef-alpha", "targetRef": "alpha"}]

This is an optional field excerpt to add to the request, not a standalone request. Each endpoint must have a unique nonempty ID in its inventory; mappings must be one-to-one. An invalid mapping refuses the request. An explicit mapping records your assertion of correspondence, not independently verified software identity. Missing or duplicate IDs and ambiguous PURLs remain visible as records that were not compared.

Use {"demo":true} for a fixed synthetic example without a customer event charge. Demo forbids the keys original, converted and mapping, even with null or empty values. A customer pair requires both document objects. URLs, archives, filesystem paths and executable inputs are not alternatives.

What the receipt covers

For matched records, the receipt compares exact declared name, version and PURL strings, plus a single selected SHA256 digest on each side. Hexadecimal digest case is ignored; name/version/PURL case and whitespace are retained. Multiple selected PURLs or SHA256 entries are ambiguous, even if identical. Missing values are distinguished from empty values; malformed supported data is refused.

It compares source DEPENDS_ON and inverse DEPENDENCY_OF with explicit target dependencies[].ref -> dependsOn[] edges. Both endpoints must be eligible and mapped. It does not infer transitive dependencies. Missing target entries, absent dependsOn and explicit empty arrays remain distinct: a missing graph declaration does not establish that the software has no dependencies. Duplicate target entries with the same ref are ambiguous.

Fact and edge findings use preserved, changed, removed, added, not_declared or not_compared as applicable. A removed declaration describes the supplied pair; it does not prove removal of actual software or a software dependency. Unmatched records do not prove software addition or removal.

Nested components, services, provides, specialized relationships, external-document references, non-package elements, other hashes, licenses, CPEs, group, properties/extensions and other uncovered fields are inventoried as exclusions. Excluded subtrees are wholly unexamined. A target-only edge associated with a specialized source relationship is not compared rather than flattened into an addition. Exclusions identify paths and keys without copying their values.

Read the result

A receipt uses coverage version sbom-pair-1 and these typed fields:

FieldHow to use it
sourceDigest, targetDigestBind the full parsed inputs to this comparison.
status, useful, hasUncertaintyRead the outcome, whether any declared fact/edge was actually compared, and independent uncertainty.
correspondenceInspect source/target IDs and paths, match status, basis (exact_purl or explicit_mapping), reason and any owner action.
fieldFindingsInspect field, status, IDs, basis, sourcePaths/targetPaths, declared sourceValue/targetValue, reason and any owner action.
dependencyFindingsInspect endpoint IDs/refs, status, evidence paths, mapping bases and declarationState (missing, empty or present) where applicable.
coverageCheck coveredFields, mapped/unpaired and fact/edge counts, plus exclusions and their paths, keys, reasons and actions.
ownerActionsFollow the collected record-specific repair or clarification actions.

The result schemas reject additional properties in the report and its nested records. Only explicitly nullable fields, such as an unavailable ID, declared value or action, may be null. A refusal is a separate result with status, useful=false, reason, path and nullable limit/observed; it has no comparison groups.

StatusMeaning
covered_preservedMatched covered declarations agree, with no unresolved covered items or unpaired records. Exclusions remain visible.
differencesAt least one covered declaration changed, was removed or was added. Uncertainty may also exist.
inconclusiveNo definite difference, but correspondence or covered facts/edges remain unresolved, or no records matched.
refusedInvalid input, an invalid mapping or a resource limit prevents a complete receipt. The reason/path/limit result omits offending values.

Always inspect hasUncertainty independently of status, then read coverage and owner actions. Exclusions alone do not set hasUncertainty. Actions identify evidence paths and specific repairs or confirmations, such as restoring a declared target version or confirming an intentional replacement. Paths are JSON Pointers into the supplied artifacts.

Selected output example

This selected excerpt comes from the retained synthetic owner QA changed-envelope case, not the input example above or a customer run. It shows one actual changed finding and its associated action; it is not the complete response. The full receipt also includes other findings, correspondence, coverage and exclusions.

{
"status": "differences",
"useful": true,
"hasUncertainty": false,
"fieldFindings": [
{
"basis": "exact_purl",
"field": "name",
"ownerAction": "Restore target name for SPDXRef-alpha / alpha from 'alpha-renamed' to 'alpha', or confirm intentional replacement; check /original/packages/0 and /converted/metadata/component (covered declared fact differs).",
"reason": "covered declared fact differs",
"sourceId": "SPDXRef-alpha",
"sourcePaths": [
"/original/packages/0/name"
],
"sourceValue": "alpha",
"status": "changed",
"targetPaths": [
"/converted/metadata/component/name"
],
"targetRef": "alpha",
"targetValue": "alpha-renamed"
}
],
"ownerActions": [
"Restore target name for SPDXRef-alpha / alpha from 'alpha-renamed' to 'alpha', or confirm intentional replacement; check /original/packages/0 and /converted/metadata/component (covered declared fact differs)."
]
}

Retrieve the complete REPORT from the run's default key-value store, or its identical default-dataset item, to inspect every finding and exclusion. Reuse that stored result instead of starting another run.

Document hashes bind the full parsed document, including excluded content. SHA256 uses UTF-8 JSON with sorted object keys, compact separators, direct Unicode and no nonfinite numbers. Object-key order and whitespace do not change these digests; array order does. These are not raw-file hashes or a claim of RFC canonicalization. Raw duplicate JSON keys and original formatting cannot be recovered after platform parsing.

The full receipt is written to the default key-value store at REPORT, followed by one identical item in the default dataset. The output tab links to both. Retrieve either stored result instead of starting another run. A receipt establishes neither full schema conformance, inventory truth, vulnerability/license meaning, compliance, lossless conversion nor recipient acceptance.

Recover and retain this run's evidence

  1. Use your authorized Apify caller to start asynchronously. Save the returned run id and a caller-generated request key in your own records before proceeding; retain defaultKeyValueStoreId and defaultDatasetId from the run response.
  2. Check GET /v2/actor-runs/RUN_ID with that saved ID (run API). If a wait or retrieval times out, check the same run again. A failed or timed-out run can still have stored output; inspect it before deciding what to do.
  3. Retrieve the authoritative full receipt with GET /v2/key-value-stores/STORE_ID/records/REPORT, using that run's defaultKeyValueStoreId as STORE_ID (record API). Its equal dataset item is available at GET /v2/datasets/DATASET_ID/items?format=json, using defaultDatasetId (dataset items API). Check REPORT during failure recovery even if dataset delivery failed.
  4. Export the full typed JSON, parse it and verify the input binding and decision-required evidence before acting or cleaning up. Keep coverageVersion, sourceDigest and targetDigest with the receipt; these digests bind parsed documents, not raw files. Read useful, hasUncertainty, findings, coverage and exclusions separately before deciding which declarations need repair.

Do not silently POST again after a failed retrieval. If the initial start response was lost and no run ID is known, reconcile your authorized run history against your recorded request and input before considering a paid restart. A missing response does not prove no run started; this workflow promises no universal start idempotency.

A table or optional dataset field projection can support a limited notification, but it is not the full report. Retain the run/storage IDs, the identity and version/profile fields above, and relevant coverage; retrieve omitted detail from this same run before making a detailed decision.

Selective cleanup

After the run is terminal, no restart is planned and your exported evidence has been parsed and verified, you may remove authorized copies you no longer need. Use your saved exact storage IDs, never a latest-run shortcut or an assumed shared store. See Apify's record deletion and dataset deletion references for platform operations, which were not exercised in this Actor's QA: deleting INPUT leaves REPORT; deleting REPORT does not delete the dataset. Input records, REPORT records, dataset items and external copies are separate. Removing one does not erase logs, exports, saved task input, source files or customer copies, or guarantee provider-wide erasure.

Limits

All boundaries are inclusive. Invalid or oversized input is refused rather than truncated; a complete receipt that cannot fit is refused without charging a partial result.

ResourceMaximum
Source packages500
Target records, including metadata.component500
Explicit mappings500
Raw source relationships2,000
Raw target dependsOn entries2,000
Each serialized document1,048,576 UTF-8 bytes (1 MiB)
Complete serialized request2,200,000 UTF-8 bytes
Request JSON value/container nodes50,000
Request depth, root at depth 132
Any string, including keys4,096 Unicode codepoints
Complete serialized receipt4,194,304 compact UTF-8 bytes (4 MiB)

Byte limits use the parsed-value serialization recipe described above. Repeated raw edges still count toward raw limits. Excluded content also counts toward byte, node, string and depth limits. The initial platform envelope is 256 MiB memory and a 60-second timeout. It is not a guarantee that every allowed input completes.

Price and failure behavior

The current price is $0.05 per complete useful receipt, using one report-produced event after both output writes complete. The pricing contract excludes automatic Actor-start and dataset-item fees; platform operating cost is separate and is not passed through as an additional agentic usage charge.

useful=true requires at least one actually compared declared covered fact or edge. Preserved, changed, removed or added findings can qualify. Unresolved-only and all-not_declared receipts, demo and refusals have no customer event charge. A partially compared inconclusive receipt can be useful and chargeable. An unpriced run may store a useful receipt without a fee. Missing paid-event capacity refuses a priced request before potentially billable computation; demo bypasses this capacity check.

Storage failure stops before charging; a failed dataset write can still leave REPORT available. Only an integer charged_count of 1 confirms SDK event acceptance, which does not establish customer payment or settlement. A charge error after storage can leave a receipt available while billing remains unresolved. Inspect the existing report and provider record before rerunning. There is no automatic retry or exactly-once guarantee across crashes or independent reruns; a rerun is an independent request. Report content alone proves no payment.

Data handling and alternatives

Send only artifacts you are permitted to transmit to Apify. Normal platform input/output retention applies: uploaded originals may persist. Covered IDs, names, versions, PURLs and digest values intentionally appear in the receipt. Excluded values are omitted from the receipt but may still be present in retained Actor input. No ephemeral processing, automatic deletion or redaction of the uploaded originals is promised.

Original-format generation where possible, independent SBOM validation, native sbomlyze comparison and authorized recipient import form a strong complete alternative. A restricted HTTP/MCP caller may find one hosted receipt convenient, but comparative savings, quality superiority, willingness to pay and external demand have not been measured.