Export-Schema
Diese Seite ist das Schema für den vollständigen Datenexport: was das Bundle enthält und welche Form jeder Datensatz hat. Wie du einen Export startest, ihn prüfst und welche Grenzen gelten, steht auf der Seite zum Datenexport. §9 des Auftragsverarbeitungsvertrags verweist hierher.
Aufbau des Bundles
export-<your-org-slug>-<YYYY-MM-DDTHH-MM-SS-mmmZ>.tar.gz
├── VERIFY.md — step-by-step verification recipe
├── manifest.json — every file below, SHA-256 and size
├── manifest.json.intoto.jsonl — DSSE-signed in-toto Statement over manifest.json
├── audit.ndjson — your org's audit events, last 90 days
├── access-log.ndjson — your registry access log (package and container downloads, uploads and deletes; CI cache hits are in pulled-versions.ndjson)
├── bundles/
│ ├── <repo>.bundle — git bundle: full history, every ref
│ └── <repo>.empty — instead of a bundle, for a repository with no commits (zero bytes)
├── findings/ — scan findings, see "Scan findings, policy, attestations and SBOMs" below
├── policy/ — package policy, verdicts, exceptions and scanner settings
├── attestations/ — build provenance and release attestations, with their signatures
├── sboms/ — repository and container-image SBOMs, with an index
└── metadata/
├── packages.ndjson — package inventory, see "Packages" below
├── packages-files.ndjson — every file of every package version
├── packages-container-tags.ndjson — container image tag → manifest digest
├── components.ndjson — third-party component inventory, see "Component inventory" below
├── deployments.ndjson — deployments your CI/CD reported, see "Deployments" below
├── pulled-versions.ndjson — package versions pulled per day and consumer, see "Pulled versions" below
└── <repo>/
├── repo.ndjson — repository settings, description, topics
├── issues.ndjson — every issue, open and closed
├── pulls.ndjson — every pull request, open and closed
├── comments.ndjson — issue and pull-request comments
├── labels.ndjson
├── milestones.ndjson — open and closed
├── releases.ndjson — release metadata; see "Release assets" below
└── lfs-manifest.ndjson — LFS object inventory, see "LFS content" belowIn Repository-Namen werden Zeichen außerhalb von a-z 0-9 . _ - durch _ ersetzt.
Verwendete Standards:
- Repositorys: das native Format
git bundlevon Git.git clone <bundle>stellt das Repository vollständig wieder her, einschließlich Historie, Branches und Tags. Ein Repository ohne Commits hat nichts zu bündeln und erscheint stattdessen als leere Datei<repo>.empty. - Issues, Pull Requests und die übrigen Dateien in
metadata/: NDJSON, ein JSON-Objekt pro Zeile, in derselben Form, in der die Forgejo-API jedes Objekt zurückgibt. - Audit-Log: NDJSON, ein Ereignis pro Zeile (
id,action,actor,fields_json,created_at). Dieselbe Form wie der interne Audit-Stream von fremforge. - Registry-Zugriffslog: NDJSON, älteste zuerst, ein Ereignis pro Zeile in der Form, die
GET /orgs/{slug}/access-logzurückgibt, mit Client-IPs und Logins so, wie sie erfasst wurden. Es umfasst alles, was innerhalb der Aufbewahrungsfrist deines Audit-Logs noch gespeichert ist. Siehe Registry-Zugriffslog. - Integrität:
manifest.jsonführt jede Datei mit ihrem SHA-256-Hash und ihrer Größe auf. Das Manifest ist mit dem Ed25519-Builder-Schlüssel von fremforge DSSE-signiert. Die Signatur liegt inmanifest.json.intoto.jsonlund lässt sich mitopenssl,jq,python3undcurlgegen die öffentliche Vertrauensbasis unterhttps://www.frem.sh/.well-known/slsa-trust-root.jsonprüfen, ganz ohne Werkzeuge von fremforge. Die vollständige Anleitung steht inVERIFY.mdim Bundle und in §„Das signierte Manifest prüfen“ auf der Seite zum Datenexport. Es ist dieselbe Vertrauensbasis, die für SLSA-Build-Attestierungen veröffentlicht wird: ein Schlüssel, zwei Prädikattypen, keine Abhängigkeit von Sigstore.
Keine proprietären Formate. Jedes Artefakt im Bundle lässt sich mit gängigen Open-Source-Werkzeugen lesen. Eine CLI von fremforge ist nicht nötig.
Pakete
metadata/packages.ndjson ist das Inventar der Paket-Registry deiner Organisation: eine Zeile pro Paketversion, mit ihrem type (container, npm, maven, pypi, generic, …), name und version, so wie die Paket-API von Forgejo sie auflistet.
metadata/packages-files.ndjson führt jede Datei jeder dieser Versionen auf, eine Zeile pro Datei:
| Feld | Bedeutung |
|---|---|
owner, type, name, version | die Paketversion, zu der die Datei gehört |
file_id, file_name | Kennung und Name der Datei in der Registry |
size | Größe in Bytes |
sha256 | SHA-256 der Datei; zusätzlich sha512, wo die Registry einen erfasst |
download_path | Pfad auf frem.sh, der genau diese Datei mit einem API-Token (Authorization: token …) herunterlädt; die Registry kann mit einer Weiterleitung zum Objektspeicher antworten. null für Registry-Typen, deren Datei-URL sich nicht allein aus dem Inventar ableiten lässt (zum Beispiel Maven); verwende für diese web_path |
web_path | der Download-Link der Datei auf ihrer Paketseite, für einen angemeldeten Browser |
Bei Container-Images ist eine Paketversion ein Tag (oder, bei einem Manifest ohne Tag wie einer Plattform eines Multi-Arch-Images, der Digest selbst). metadata/packages-container-tags.ndjson ordnet jedem Tag seinen Manifest-Digest zu (owner, name, tag, manifest_digest), den docker pull <image>@sha256:… und andere OCI-Werkzeuge verwenden. Die Layer und die Konfiguration des Images erscheinen in packages-files.ndjson als Dateien, die nach ihrem Digest benannt sind; download_path zeigt auf die Endpunkte /v2/…/blobs/… und /v2/…/manifests/… der Registry.
Eine heruntergeladene Datei gegen das Inventar prüfen:
row=$(jq -c 'select(.name=="@acme/lib" and .version=="1.2.0")' metadata/packages-files.ndjson)
curl -sSL -H "Authorization: token $TOKEN" -o pkg.bin "https://frem.sh$(jq -r .download_path <<<"$row")"
echo "$(jq -r .sha256 <<<"$row") pkg.bin" | sha256sum -c -Das Inventar ist immer im Bundle. Die Paketdateien selbst kommen nur auf Wunsch, als separates Archiv: siehe §„Paketinhalte“.
Komponenteninventar
metadata/components.ndjson ist das Inventar der Komponenten von Drittanbietern deiner Organisation: eine Zeile pro Komponente und Ort, an dem sie verwendet wird oder wurde, dieselben Zeilen, die GET /orgs/{slug}/components/usages liefert. Beendete Verwendungen werden 180 Tage aufbewahrt und sind enthalten, sodass die Historie mit dir geht.
| Feld | Bedeutung |
|---|---|
purl, ecosystem, name, version | die Komponente, als Package-URL und ihre Bestandteile |
licence, licence_source | der Lizenzausdruck und woher er gelesen wurde |
subject_kind, subject_name, subject_ref | wo sie verwendet wird: das Repository, Paket oder Image und die Ref oder der Digest |
image_tags | bei einem Image die Tags, die darauf zeigen; sonst leer |
source_repo | das Repository, das sie gebaut hat, soweit bekannt |
is_direct | true für eine direkte Abhängigkeit, false für eine transitive, null, wo die SBOM es nicht angibt |
environment, environment_source | die Umgebungsklasse (sandbox, development, test oder production) und wie sie gesetzt wurde |
is_current, first_seen_at, last_seen_at, removed_at | ob die Verwendung aktuell ist und wann sie zuerst und zuletzt gesehen und entfernt wurde |
Deployments
metadata/deployments.ndjson enthält jedes Deployment, das deine CI/CD mit POST /orgs/{slug}/repos/{repo}/deployments gemeldet hat, eine Zeile pro Deployment, aufsteigend nach Kennung.
| Feld | Bedeutung |
|---|---|
id | die Kennung des Deployments |
repository, environment, environment_class | das Repository (owner/name), der von dir vergebene Umgebungsname und seine Klasse (sandbox, development, test, staging oder production) |
ref, sha, task, description | Ref und Commit, die deployt wurden, die Aufgabe (deploy, sofern du keine andere angegeben hast) und deine Beschreibung |
image_digests, packages | die Image-Digests und Package-URLs, die das Deployment nennt |
state | der letzte Status: pending, queued, in_progress, success, failure, error oder inactive |
creator_kind, creator, run_id | wer es gemeldet hat (job, robot, user oder token), dessen Name und bei einem Job der Actions-Run |
created_at, updated_at | wann es gemeldet und zuletzt geändert wurde |
statuses | jeder Status, neueste zuerst: state, description, log_url, environment_url, creator_kind, creator, created_at |
Gezogene Versionen
metadata/pulled-versions.ndjson ist der Pull-Zensus: eine Zeile pro UTC-Tag, Paketversion und Verbraucher, für die Tage, die innerhalb der Aufbewahrungsfrist deines Zugriffslogs noch gespeichert sind. Seit dem 13.10.2026 ist er die einzige Aufzeichnung der Downloads, die ein CI-Job über den Abhängigkeits-Proxy gemacht hat und die aus dessen Cache bedient wurden; diese stehen nicht in access-log.ndjson. Es sind die Zeilen, die GET /orgs/{slug}/components/pulled aufsummiert; die Advisories, die dieser Endpunkt hinzufügt, sind nicht in der Datei.
| Feld | Bedeutung |
|---|---|
day | der UTC-Tag, YYYY-MM-DD |
origin | registry für deine eigenen Pakete, proxy für den Abhängigkeits-Proxy |
ecosystem, name, version | Pakettyp (npm, pypi, maven, nuget, go, container, …), Name und Version |
consumer | wer es gezogen hat: kind (job, robot, bot, user oder anonymous), name (das Repository des Jobs, der Name des Robots oder der Login; null bei anonym), id, bei einem Robot sein login und bei einem Job run_ids, die Actions-Runs, die es an diesem Tag gezogen haben (neueste zuerst, höchstens 100; leer vor dem 13.10.2026) |
pulls | erfolgreiche Downloads an diesem Tag |
first_seen_at, last_seen_at | der erste und der letzte davon, UTC mit Mikrosekunden |
Scan-Befunde, Richtlinie, Attestierungen und SBOMs
Jeder Export enthält die Sicherheitsdaten, die fremforge über deine Organisation führt, als NDJSON (ein JSON-Objekt pro Zeile), wie jede andere Datei vom signierten Manifest abgedeckt. Jede Zeile ist der vollständige Datensatz, den fremforge speichert, ohne die interne Mandanten-ID und Speicherpfade; verworfene Befunde sind enthalten, mit Angabe, wer sie verworfen hat, warum und bis wann. Zeilen, die ein Registry-Paket betreffen, tragen ein Objekt package (type, owner, name, version, file, blob_sha256).
findings/
├── sast.ndjson — static analysis (rule, file, line, severity)
├── dependencies.ndjson — dependency vulnerabilities, with CVSS and EPSS where known
├── dependency-dismissals.ndjson — repository-wide dependency dismissals
├── licences.ndjson — licence findings, each with its licence policy decision
├── container-images.ndjson — container image vulnerabilities
├── container-image-dismissals.ndjson
├── secrets.ndjson — rule, file, line and fingerprint; the secret value is never stored
├── malware-uploads.ndjson — malware found in uploads
├── malware-dependencies.ndjson — known-malicious dependencies
├── malware-container-layers.ndjson — per image manifest, each layer's malware verdict
├── packages.ndjson — vulnerabilities found in your registry packages
├── package-licences.ndjson — declared and detected licences of your registry packages
└── sha-pinning.ndjson — workflow actions not pinned to a commit
policy/
├── package-policy.ndjson — your package policy (mode, thresholds, licence lists, minimum age)
├── package-policy-rules.ndjson — allow and deny rules
├── package-policy-approvers.ndjson
├── package-policy-verdicts.ndjson — the current verdict for each package file, with reasons
├── package-gate-decisions.ndjson — downloads blocked, or that would have been blocked in shadow mode
├── exceptions.ndjson — policy exceptions, who requested and who approved them
├── malware-overrides.ndjson
├── package-access-packages.ndjson — per-package access: each configured package (mode, inheritance)
├── package-access-grants.ndjson — per-package access grants (teams, Actions repositories)
├── package-protection-rules.ndjson — protected package names
├── scan-overrides.ndjson — per-repository scanner mode overrides
└── settings/ — each scanner's org settings (sast, dependencies, licences, container-images, secrets),
and licence-repo-overrides.ndjson: per-repository licence policy overrides
and package-access.ndjson: the per-package access default
and retention.ndjson: one line per evidence retention class, with what you set,
what applies, the default, the bounds and whether a legal hold is active
attestations/
├── build-provenance.ndjson — one line per build provenance attestation
├── build-provenance/<id>.intoto.jsonl — its DSSE envelope (the Ed25519 signature)
├── build-provenance/<id>.sigstore.json — its keyless Sigstore bundle, where one was made
├── releases.ndjson — release attestations: subjects, the frozen release manifest, status, and envelope_path
├── sbom-ingest.ndjson — attestations uploaded together with an SBOM
└── sbom-ingest/<sbom id>.intoto.jsonl
sboms/
├── index.ndjson — one line per SBOM, see below
├── repos/<id>.cdx.json — a repository SBOM, CycloneDX (<id>.spdx.json for SPDX)
└── images/<id>.cdx.json — a container image SBOM- Signaturen reisen mit den Attestierungen. Jeder Umschlag lässt sich gegen dieselbe Vertrauensbasis prüfen wie das Bundle, mit dem Skript aus §„Das signierte Manifest prüfen“, das du auf den Umschlag statt auf
manifest.json.intoto.jsonlrichtest (lass die Prüfungen vonmanifestSha256undpredicateTypeweg, die nur für Export-Bundles gelten). Die Sigstore-Bundles sind gegen fremforges eigenes Fulcio und die eigene Zeitstempelstelle signiert, nicht gegen das öffentliche Sigstore; siehe SLSA-Provenienz. - Eine fehlende Signatur wird gezeigt, nicht versteckt. Eine Zeile mit
"envelope_status": "missing"ist eine Attestierung, deren Signaturobjekt beim Export nicht mehr im Speicher lag. Jeder andere Speicherfehler lässt den Export fehlschlagen. - Container-Layer. Das Malware-Urteil eines Layers gehört zu seinem Inhalt, daher wird ein Layer, den ein anderes Image mitnutzt, mit seinem Urteil unter jedem deiner Manifeste aufgeführt, das ihn verwendet. Images, die über den Abhängigkeits-Proxy gezogen wurden, sind nur aufgeführt, solange deine Organisation das ClamAV-Scanning von Proxy-Abrufen eingeschaltet hat; ist es aus (der Standard), werden sie nicht mit ClamAV gescannt und haben keine Layer-Urteile.
- Release-Attestierungen gibt es für Repositorys mit unveränderlichen Releases. Ein Release, dessen
statusnichtsignedist, hat keinen Umschlag (envelope_pathistnull). - SBOMs.
sboms/enthält jede SBOM, die fremforge für deine Repositorys (Release- und Default-Branch-Builds, ob hochgeladen oder vom zentralen Scan erstellt) und für deine Container-Images (das Inventar der Registry pro Manifest) speichert, als das Dokument selbst. Ein Repository-Build hat meist sowohl ein CycloneDX- als auch ein SPDX-Dokument; siehe SBOMs. Jede Zeile vonsboms/index.ndjsonist der gespeicherte SBOM-Datensatz (id,subject_kindrepooderimage,format,repo_full_nameoderartifact_name,release_tag,image_tags,manifest_digest,created_at,sha256_digestund der Rest des gespeicherten Datensatzes, ohne Speicherpfade) plus drei Felder zur Datei in diesem Bundle:document_path,document_sha256unddocument_status. Letzteres istok, wenn das Dokument mit dem beim Speichern erfassten SHA-256 übereinstimmt,digest_mismatch, wenn nicht (die Bytes werden trotzdem exportiert, und beide Digests stehen in der Zeile), undmissing, wenn das Dokument nicht mehr im Speicher lag. Jeder andere Speicherfehler lässt den Export fehlschlagen. - Paket-SBOMs sind nicht in
sboms/. Die SBOM jeder Datei eines Registry-Pakets liegt neben der Datei im optionalen Archiv der Paketinhalte.