Repository access views

As part of adding repository hosting to Debusine, it needs to be able to serve repositories from debian:archive collections in an apt-compatible format.

Domains

Since Debusine’s Set-Cookie header doesn’t include a Domain attribute, its cookies are not available to subdomains. It should therefore be safe to run repositories from a subdomain of DEBUSINE_FQDN: content served from that subdomain will not be able to run session fixation attacks on its parent domain.

A reasonable default would be deb.{DEBUSINE_FQDN}: shorter than repositories, not protocol-specific like ftp, and familiar from deb.debian.org. However, we can include a setting such as DEBUSINE_DEBIAN_ARCHIVE_FQDN to allow instances to override this.

Repositories will normally be served over HTTPS, but public repositories may also be served over HTTP. This is sometimes useful for bootstrapping minimal environments that lack certificates.

URL paths

The basic path to a repository is /{scope}/{workspace}, relying on the fact that archive collections are singletons. Suites in the archive are mapped onto subdirectories of dists/ as usual.

Todo

In future, we might also provide the ability to map particular repositories onto different URLs.

by-hash paths are handled specially: they are translated into a search for a repository index in the correct suite with the correct path and checksum. That repository index need not be the active index for its path in the suite; it can be served as long as the suite’s full_history_retention_period has not expired.

/{scope}/{workspace}/{timestamp}, where timestamp has the format YYYYMMDDTHHMMSSZ, e.g. 20250529T133100Z for 13:31 UTC on 29 May 2025, addresses the state of the repository as it existed at timestamp. This is done by looking up collection items that have created_at and removed_at fields bracketing the given timestamp, rather than just those that are active (with removed_at unset), and can be done as long as the suite’s full_history_retention_period has not expired. This URL format is compatible with snapshot.debian.org and snapshot.ubuntu.com; like those services, a user can request any timestamp as a snapshot ID, and the server will provide the indexes and other files that were current at that point in time.

Todo

Add a Snapshots field to generated Release files, pointing to the corresponding URL format.

Todo

Once we’ve defined how repository signing works, we should also publish each repository’s public keys in some standard location.

Authentication and authorization

APT only handles HTTP Basic Authentication, so we’re stuck with that mechanism, but we can still use our existing user tokens: users may use their user name with their user token acting as a password. Downloading files from a repository requires the “viewer” role on the workspace.

Cache control

Responses to different URLs in a repository should be cached in different ways, and Debusine sends the Cache-Control response header to inform HTTP caches of this.

by-hash files under dists/, and all files resulting from a timestamp-specific query are immutable: they may be removed, but they won’t be replaced with different contents at the same URL. This is also true for files under pool/ in archives where may_reuse_versions is false. For these files, Debusine sends Cache-Control: max-age=31536000 (i.e. 365 days, an arbitrary long period).

For other files, Debusine sends Cache-Control: max-age=1800, proxy-revalidate to indicate that shared caches should revalidate responses before reuse if they are older than half an hour. (This period is also arbitrary, but should be a good starting point.)

Debusine also sends Vary: Authorization for all responses to repository URLs, since its responses depend on whether the requester has the “viewer” role on the workspace.

Examples

If we were to create an archive collection in debian/base on debusine.debian.net and generate indexes for its suites, then APT configuration for it might look something like this:

Types: deb deb-src
URIs: https://deb.debusine.debian.net/debian/base
Suites: bookworm
Components: main contrib non-free non-free-firmware

A snapshot of it from the start of May 2025 might be as follows (in this case we have to add the snapshot ID to the URL, as we don’t control the Release file and can’t add a Snapshots field to it):

Types: deb deb-src
URIs: https://deb.debusine.debian.net/debian/base/20250501T000000Z
Suites: bookworm
Components: main contrib non-free non-free-firmware

An experiment workspace based on debian/developers might look like this:

Types: deb deb-src
URIs: https://deb.debusine.debian.net/debian/developers-test
Suites: sid
Components: main

Or a snapshot, once Debusine’s generated Release files gain a Snapshots field:

Types: deb deb-src
URIs: https://deb.debusine.debian.net/debian/developers-test
Snapshot: 20250501T000000Z
Suites: sid
Components: main