Skip to content

Adds WORM evidence storage for history events and snapshots#345

Merged
aaronzi merged 5 commits into
eclipse-basyx:mainfrom
aaronzi:main
Jun 8, 2026
Merged

Adds WORM evidence storage for history events and snapshots#345
aaronzi merged 5 commits into
eclipse-basyx:mainfrom
aaronzi:main

Conversation

@aaronzi

@aaronzi aaronzi commented Jun 5, 2026

Copy link
Copy Markdown
Member

Summary

Adds WORM-compatible history evidence support for AAS v3.2 history.

The default integrity architecture is now:

PostgreSQL history tables -> hash chain -> signed/unsigned manifest -> S3-compatible WORM object storage

This keeps the existing $history and $recent-changes HTTP APIs unchanged, while adding external evidence artifacts for tamper detection, verification, and bounded recovery.

Changes

  • Added EvidenceStore abstraction for immutable evidence artifacts.
  • Added S3-compatible evidence store using AWS SDK for Go v2.
  • Added fail-closed synchronous history_event artifact writes during history append:
    • object-store write happens before PostgreSQL commit
    • PostgreSQL transaction rolls back if evidence storage fails
    • receipt is stored in PostgreSQL only after the object write succeeds
  • Added per-row WORM history_event artifacts containing:
    • history payload, snapshot or diff
    • row hash metadata
    • audit/source fields where currently available
    • effective_diff for attribution, even when the stored recovery payload is a full snapshot
  • Added signed/unsigned history manifests for history ranges.
  • Added PostgreSQL catalog tables for evidence manifests and artifacts via 1_1_3.sql.
  • Added verifier/publisher CLI: cmd/historyevidenceverifier.
  • Added S3/MinIO example configuration to BaSyxHistoryAuditGuardedExample.
  • Kept IntegrityAnchor / external_anchor as optional future extension point for immudb, Rekor, Trillian, or timestamping.
  • Updated developer/user documentation for evidence storage, verification, recovery limits, and operational caveats.

Important Behavior

When evidence storage is enabled, successful API writes require both PostgreSQL and WORM evidence storage to succeed. If the S3-compatible backend is unavailable, rejects retention metadata, or times out, the mutation fails and PostgreSQL rolls back.

Recovery from WORM evidence is bounded by history.fullSnapshotInterval:

  • 1: every row is recoverable as a full WORM snapshot
  • >1: recovery starts from the latest WORM snapshot and replays WORM-stored diffs

The effective_diff field prevents attribution confusion when a full snapshot checkpoint is written for a small user change.

Security / Compliance Notes

This feature strengthens integrity protection, traceability, auditability, recovery evidence, and unauthorized modification detection. It does not by itself make a deployment NIS2-compliant.

Production deployments still need correctly operated WORM storage, restricted IAM, retention policy, key management, monitoring, audit logs, backups, and operational procedures.

MinIO is included only as a local/test S3-compatible Object Lock backend. Production targets should use an operated S3-compatible WORM service, for example AWS S3 Object Lock.

- Add WriteHistoryEvidence function to verify history ranges and store event/snapshot artifacts.
- Introduce EventArtifactCandidate and SnapshotArtifactCandidate structures for managing artifacts.
- Implement functions to load event and snapshot artifact candidates from the database.
- Create HistoryManifest and associated functions for building and validating manifests.
- Add ManifestJWSSigner for signing manifests with RSA keys.
- Implement artifact storage and retrieval mechanisms for both events and snapshots.
- Ensure proper error handling and validation throughout the evidence storage process.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a WORM (write-once, read-many) evidence pipeline for BaSyx history data, enabling deterministic per-row history_event artifacts plus optional snapshot checkpoint and signed/unsigned range manifests stored in an S3-compatible object store, with PostgreSQL cataloging and verification tooling.

Changes:

  • Add core evidence types, manifest generation/signing/decoding, and PostgreSQL catalog persistence + verification for history ranges.
  • Implement an S3-backed EvidenceStore with Object Lock retention requirements and wire synchronous evidence writes into the history append transaction path.
  • Add configuration surface (YAML + env), schema migration v1.1.3, a CLI (cmd/historyevidenceverifier), updated docs/examples, and CI coverage for the new history package tests.

Reviewed changes

Copilot reviewed 34 out of 35 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/common/jws/jws.go Add RS256 JWS signing helper used for manifest signing.
internal/common/history/snapshot_artifact.go Build and load snapshot checkpoint artifacts for evidence storage.
internal/common/history/manifest.go Generate canonical history range manifests and deterministic range digests.
internal/common/history/manifest_artifact.go Serialize manifests as unsigned JSON or compact RS256 JWS and decode stored artifacts.
internal/common/history/history_event_artifact.go Build/load per-row history_event evidence artifacts from DB history rows.
internal/common/history/evidence_writer.go Orchestrate verification, artifact storage (events/snapshots/manifests), and catalog recording.
internal/common/history/evidence_verifier.go Verify hash chains, manifest consistency, evidence receipts, and optional object-store hashes.
internal/common/history/evidence_types.go Define evidence store interfaces, artifact/receipt/reference structs, manifest structs.
internal/common/history/evidence_test.go Add unit tests for manifest determinism/signing, S3 receipt behavior, writer/verifier paths.
internal/common/history/evidence_store_s3.go Implement S3 evidence backend with Object Lock retention + verification reads.
internal/common/history/evidence_hash.go Provide SHA-256 helper for evidence artifact hashing.
internal/common/history/evidence_catalog.go Persist evidence manifest/artifact receipts into PostgreSQL catalog tables.
internal/common/history/config.go Add evidence configuration (enabled/provider/store/timeout) and provider initialization helper.
internal/common/history/append.go Integrate synchronous evidence write + catalog insert into history append transaction flow.
internal/common/history/append_test.go Add tests asserting evidence writes happen pre-commit and failures roll back DB tx.
internal/common/database.go Bump schema version constant to v1.1.3.
internal/common/configuration.go Add config schema/env overrides/defaults/validation for evidence + future integrity anchor.
internal/common/configuration_test.go Add tests for evidence defaults, env overrides, and validation behavior.
go.mod Add AWS SDK v2 deps and require gopkg.in/go-jose/go-jose.v2.
go.sum Record checksums for newly added/updated module dependencies.
examples/BaSyxHistoryAuditGuardedExample/README.md Document local MinIO Object Lock setup and evidence publish/verify workflow.
examples/BaSyxHistoryAuditGuardedExample/docker-compose.yml Add MinIO + init container and wire evidence env vars into the example.
docu/user/aas_api_v3_2.md Document new evidence-related environment variables and YAML configuration.
docu/developer/aas_v3_2_runtime.md Describe evidence pipeline, schema migration 1_1_3.sql, and runtime sequence changes.
database/patches/1_1_3.sql Add evidence catalog tables/indexes and bump DB schema to v1.1.3.
cmd/submodelrepositoryservice/main.go Initialize evidence store at service startup via history.ConfigureEvidence.
cmd/historyevidenceverifier/main.go Add CLI to write evidence artifacts and/or verify ranges and stored manifests.
cmd/digitaltwinregistryservice/main.go Initialize evidence store at service startup via history.ConfigureEvidence.
cmd/conceptdescriptionrepositoryservice/main.go Initialize evidence store at service startup via history.ConfigureEvidence.
cmd/basyxconfigurationservice/main.go Register schema patch 1_1_3.sql and adjust 1_1_2.sql version registration.
cmd/aasrepositoryservice/main.go Initialize evidence store at service startup via history.ConfigureEvidence.
cmd/aasregistryservice/main.go Initialize evidence store at service startup via history.ConfigureEvidence.
cmd/aasenvironmentservice/main.go Initialize evidence store at service startup via history.ConfigureEvidence.
.github/workflows/examples-smoke.yml Add smoke job entry for the evidence-enabled history guarded example compose file.
.github/workflows/common-tests.yml Add dedicated go test coverage run for ./internal/common/history.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/common/history/evidence_writer.go
Comment thread internal/common/history/manifest_artifact.go
Comment thread internal/common/history/snapshot_artifact.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 34 out of 35 changed files in this pull request and generated 1 comment.

Comment thread internal/common/history/evidence_catalog.go

@Martin187187 Martin187187 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is audit information intentionally not added yet?
i get this in minio: "audit":{"actor_issuer":"","actor_subject":"","authorization_result":"","client_id":"","correlation_id":"","endpoint":"","http_method":"","matched_rule_id":"","operation":"","policy_id":"","request_id":"","source_ip":"","user_agent":""}

@Martin187187

Copy link
Copy Markdown
Contributor
image Deleted Objects are shown no matter if "Show deleted objects" is ticked or not. Maybe this can be configured when requesting the histroy update to minio?

@aaronzi

aaronzi commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

is audit information intentionally not added yet?

Yes, that will be introduced with the next PR

@aaronzi

aaronzi commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

Deleted Objects are shown no matter if "Show deleted objects" is ticked or not. Maybe this can be configured when requesting the histroy update to minio?

Deleted here means deleted from the WORM storage, not deleted in Terms of an AAS was deleted. The WORM storage is also append only. You can't delete stuff from there. And even if you do, you can not fully delete it and will always see it if you check this checkbox.

Btw, history ist not fetched from the WORM storage. It always comes from the PostgreDB. The WORM storage is a recovery and traceability storage, not for providing the data for the /$history endpoints

@Martin187187

Copy link
Copy Markdown
Contributor

Error updating Property "PcfCO2eq"!

Status: 500
Message Type: Error
Correlation ID: SMREPO-500-PatchSubmodelElementByPathValueOnlySubmodelRepo-InternalServerError-UpdateSubmodelElementValueOnly
Timestamp: 6/8/2026, 11:06:04 AM
Text: 500 Internal Server Error: HISTORY-EVIDENCE-APPEND-PUTARTIFACT HISTORY-EVIDENCE-S3-PUTOBJECT operation error S3: PutObject, https response error StatusCode: 0, RequestID: , HostID: , request send failed, Put "http://minio:9000/basyx-history-evidence/history-evidence/history-events/submodel_history/urn%3Afraunhofer%3Aiese%3Adte%3Asm%3Acarbonfootprint%3Adrivemotor-dm3000%3A001/14-1c8c3c43d01320f88517293cdfad5bd290c10be32a4e4fe834e33e5d60a7b909.json?x-id=PutObject": dial tcp: lookup minio on 10.89.5.1:53: no such host

I get thiss error when i start the backend wihtout minio running and trying to change a value in a submodel. Maybe 503 Service Unavailable is more fitting?

Comment thread internal/common/history/evidence_store_s3.go
Comment thread internal/common/history/evidence_verifier.go
Comment thread internal/common/history/evidence_verifier.go Outdated
@aaronzi aaronzi merged commit 4b4c444 into eclipse-basyx:main Jun 8, 2026
44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants