Registry access log
The audit log records administrative actions. The
registry access log records something else: every request a client makes to
your organisation’s package and container registry. That covers each
download, each metadata read (an npm packument, a PyPI simple index, a Maven
maven-metadata.xml), each upload and each delete, and it includes requests
that a policy blocked. Nothing is sampled.
What an event holds
| Field | Meaning |
|---|---|
occurred_at | When fremforge answered the request (UTC). |
origin | Which component saw the request: registry for the package registry. The dependency proxy, when it ships, writes proxy. |
surface | api (/api/packages/…), oci (/v2/…, the container registry) or web (a file downloaded from the web UI). |
org, package.type, package.name, package.version, package.file | What was asked for. |
package.digest | sha256:<hex> of the file or manifest that was served or stored, when the registry named it. |
action | download, metadata, upload, delete or other. |
actor | Who the registry authenticated: {type: "user" | "bot" | "anonymous", id, login}. A token or a session resolves to the user it belongs to, and Forgejo Actions jobs show as a bot. |
client_ip | The client address as fremforge’s edge saw it. It is empty when fremforge could not verify the address, for example on a request that did not come through the edge. |
user_agent | The client’s User-Agent, cut at 256 characters. |
http.method, http.status, http.bytes | The request method, the answer, and the size where it is known. Size is unknown for a download that is redirected to object storage. |
decision, decision_reason | allowed; blocked; would_block (a policy running in shadow mode would have refused it, and the request went through); or pending_refused (your package policy refuses files whose scan has not finished yet, and this file’s had not; the client got 503 with Retry-After, and a retry once the scan finishes succeeds). decision_reason names the rule that decided, for example malware, image_malware, image_cve, registry_scan:<reason> or immutable_retired (see immutable package versions). |
Never recorded: an access token, an Authorization header, a cookie or a
query string. A presigned storage URL, for example, never appears in an
event.
Reading it
With a token that carries audit:read:
curl -sS -H "Authorization: Bearer $FFP_TOKEN" \
"https://frem.sh/_app/api/v1/orgs/acme/access-log?action=download&type=npm&since=2026-10-01"Results come newest first. Pass the next value of a page as cursor to get
the next page, and stop when next is null. The cursor is a keyset, so
events that arrive while you page never shift or repeat a row. Filters:
since, until, origin, action, decision, type, name, version,
actor (a login, or anonymous) and ip. A page holds up to 500 events.
See the API reference for the full shape.
Forwarding it to your SIEM
Access events can be delivered to a SIEM endpoint in the
same signed envelope as audit events. The action is
registry.access.<action> (for example registry.access.download), and
hash_chain is null because access events are not part of the audit
hash chain. Delivery is off by default, because download traffic is far
larger than audit traffic. Turn it on per endpoint with include_access_log:
curl -sS -X PATCH -H "Authorization: Bearer $FFP_TOKEN" -H 'Content-Type: application/json' \
-d '{"include_access_log": true}' \
https://frem.sh/_app/api/v1/orgs/acme/siem/endpoints/$ENDPOINT_IDAn endpoint’s action prefixes apply to access events too. For example,
registry.access.upload forwards only uploads.
In the data export
A data export contains access-log.ndjson with every
access event fremforge still holds for the organisation, one JSON object per
line in the same shape the API returns. The file is covered by the export’s
signed manifest.
How long it is kept
Access events follow your organisation’s audit log retention: 90, 180, 365 or 730 days, set at Authentication policy → Audit log retention. The default is 90 days. Older events are deleted once a day. While a legal hold is in place, nothing is deleted.
Who can see the addresses
The access log contains personal data: your users’ logins and IP addresses. The API, the SIEM delivery and the export show both as recorded, because this is your organisation’s own record. fremforge staff tooling sees both only as keyed pseudonyms. Log lines the platform writes for its own operations carry neither.
Limits
- Git clone and fetch, and reads through the REST API (
/api/v1), are not registry requests and are not in this log yet. - Deleting a package version through the REST API
(
DELETE /api/v1/packages/...) or the web UI is not recorded here. The deletes a registry client makes under/api/packagesare recorded. - A request the platform refused before the registry answered, such as an
upload rejected by the malware scanner, has no authenticated actor and
shows as
anonymous. - Delivery from the registry to the log is batched every 2 seconds or every 500 events. If the platform is restarted mid-batch, the events of the last few seconds can be lost. Deliberate drops are logged and alarmed on our side.