Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
0b3bca2
vk-registry/dav: share the files object layer
abernardeau-wallix Nov 5, 2026
acff68c
vk-registry: add the s3 server setting
abernardeau-wallix Nov 5, 2026
64bc138
vk-registry/s3: check SigV4 credentials on /s3/
abernardeau-wallix Nov 5, 2026
ca2301f
vk-registry/files: let a write carry annotations and a precondition
abernardeau-wallix Nov 5, 2026
964fcad
vk-registry/s3: serve, store and delete objects
abernardeau-wallix Nov 5, 2026
cd01870
vk-registry/s3: list a bucket's objects
abernardeau-wallix Nov 5, 2026
0fb92b7
vk-registry/s3: decode aws-chunked uploads and check checksums
abernardeau-wallix Nov 5, 2026
df077b4
vk-registry/s3: serve byte ranges
abernardeau-wallix Nov 5, 2026
078525f
vk-registry/s3: create and delete buckets, copy and batch-delete objects
abernardeau-wallix Nov 5, 2026
967918a
vk-registry/s3: serve multipart uploads
abernardeau-wallix Nov 5, 2026
d7d7dd7
vk-registry: print a key's S3 pair
abernardeau-wallix Nov 5, 2026
7770420
vk-registry/s3: take the bucket from the host name with s3_host
abernardeau-wallix Nov 5, 2026
9dbfe34
vk-registry/s3-compat: add the external S3 conformance suites
abernardeau-wallix Nov 5, 2026
4237776
vk-registry/s3: send no checksum with a byte range
abernardeau-wallix Nov 5, 2026
d2facb4
tests: add an S3 e2e with sccache, the AWS CLI and rclone
abernardeau-wallix Nov 5, 2026
83d3c43
vk-driver/regproxy: forward /s3/ to jobs
abernardeau-wallix Nov 5, 2026
c512a9c
vk-driver/regproxy: keep the length on a HEAD answer
abernardeau-wallix Nov 5, 2026
c418c70
vk-driver/regproxy: refuse a listing the alias cannot confine
abernardeau-wallix Nov 5, 2026
012d48a
vk-driver/regproxy: do not repeat a conditional PUT
abernardeau-wallix Nov 5, 2026
7b71355
vk-registry/s3: let a write-only grant delete
abernardeau-wallix Nov 5, 2026
802953b
vk-registry/s3: require every x-amz header to be signed
abernardeau-wallix Nov 5, 2026
9cb45fc
vk-registry/s3: decode query parameter names before dispatch
abernardeau-wallix Nov 5, 2026
2b9d41b
vk-registry/s3: report a failed key in a batch delete
abernardeau-wallix Nov 5, 2026
f8ec349
vk-registry: keep s3_host away from the registry's own name
abernardeau-wallix Nov 5, 2026
effd6a8
vk-registry/s3: refuse control characters in markers and batch keys
abernardeau-wallix Nov 5, 2026
115938a
vk-registry/s3: list the buckets a prefix-scoped key may read into
abernardeau-wallix Nov 5, 2026
66f4b18
vk-registry/tests: test the cross-site write refusal
abernardeau-wallix Nov 5, 2026
ecab229
doc: say an S3 write creates its missing bucket
abernardeau-wallix Nov 5, 2026
a664572
tests: add a GitLab scenario for the S3 view through an area's alias
abernardeau-wallix Nov 5, 2026
1b67ef5
vk-registry/s3: answer ListObjectVersions as an unversioned store
abernardeau-wallix Nov 5, 2026
e3846dd
vk-registry/s3: carry x-amz-id-2 on every answer
abernardeau-wallix Nov 5, 2026
4b28d1b
vk-registry/s3: refuse an unknown Authorization scheme as malformed
abernardeau-wallix Nov 5, 2026
a15078c
vk-registry/s3: refuse a write that asks for what is not kept
abernardeau-wallix Nov 5, 2026
3edf177
vk-registry/s3: check, keep and list the checksum a write carries
abernardeau-wallix Nov 5, 2026
9062730
vk-registry/s3: read an object made of parts a part at a time
abernardeau-wallix Nov 5, 2026
3287d97
vk-registry/s3: let a refused write see its refusal
abernardeau-wallix Nov 6, 2026
c7c4218
vk-registry/s3: name the object's size on a PutObject's answer
abernardeau-wallix Nov 6, 2026
5117718
vk-registry/s3: delete only what a conditional delete names
abernardeau-wallix Nov 6, 2026
5618d0c
vk-registry/s3: complete or abort an upload one request at a time
abernardeau-wallix Nov 6, 2026
98d5191
vk-registry/s3: answer a repeated completion as the first was
abernardeau-wallix Nov 6, 2026
35de930
vk-registry/s3: page bucket listings with the markers S3 sends
abernardeau-wallix Nov 6, 2026
2e15aee
vk-registry/s3: page ListMultipartUploads by key and upload id as S3 …
abernardeau-wallix Nov 6, 2026
29f46ab
vk-registry/s3: answer InvalidURI for a path S3 cannot parse
abernardeau-wallix Nov 6, 2026
d47c8f0
vk-registry/s3: answer S3's own error codes, statuses and messages
abernardeau-wallix Nov 6, 2026
411ea11
vk-registry/s3: say a missing bucket or key before what is not served
abernardeau-wallix Nov 6, 2026
77c56ea
vk-registry/s3: answer the remaining refusals with S3's codes and order
abernardeau-wallix Nov 6, 2026
f603b1e
vk-registry/s3: check and keep XXHASH64, XXHASH3 and XXHASH128 checksums
abernardeau-wallix Nov 6, 2026
fb221a4
vk-registry/s3: hold an upload's parts and completion to its checksum
abernardeau-wallix Nov 6, 2026
9350001
vk-registry/s3: compute the checksum a copy asks for
abernardeau-wallix Nov 6, 2026
211b522
vk-registry/s3: give an upload sent without a checksum S3's CRC64NVME
abernardeau-wallix Nov 6, 2026
8d51f60
vk-registry/s3: give an upload's object S3's composite checksum
abernardeau-wallix Nov 6, 2026
9e5ceb3
vk-registry/s3: refuse an aws-chunked chunk shorter than 8192 bytes b…
abernardeau-wallix Nov 6, 2026
f1127b9
vk-registry/s3: refuse a completion whose parts but the last are unde…
abernardeau-wallix Nov 6, 2026
220e4d4
vk-registry/s3: refuse a request no operation takes before its creden…
abernardeau-wallix Nov 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,45 @@ All notable changes to virtkit will be documented in this file.

## [Unreleased]

### Added

- **The registry's plain-file area is also served as S3.** Under `/s3/` on `vk-registry`,
each top-level directory of the WebDAV `files/` area is a bucket, so `sccache`'s S3 backend
and other S3 clients can share a compiler cache or files with it: point them at
`https://<registry>/s3` with any region (a bucket is made by the first write into it, so
`sccache` needs none made beforehand), and use the registry credential (an API key, a hub
token or the shared bearer) as both the access key and the secret access key, or the shared
Basic user and its password. Objects can be written, read with conditional headers and
checksums (in every algorithm S3 has, checked on upload and kept with the object, and a
CRC64NVME computed for an upload that sends none, as S3 does), given
metadata and deleted, and listed page by page (as object versions too, for
tools that empty a bucket that way), and are the same files WebDAV and `vk registry get`
see; a key limited to a directory of a bucket can list that directory.
The chunked uploads AWS SDKs and the CLI send are taken, their signatures and checksums
checked, and objects can be read in byte ranges, as the AWS CLI downloads large files.
Buckets can be created and removed, objects copied without their bytes being stored twice
(or with the checksum a copy asks for computed from them) and deleted in batches — only while still the ETag, modification time or size a delete
names, when it names one, as S3's conditional deletes — and the configuration probes tools send before using a bucket
(versioning, ACLs, tagging and the like) are answered as for a bucket with none set, and a
write asking for one of them — encryption under the client's own key, tags, an ACL, a
storage class, a redirect, a retention lock — is refused rather than stored without it, and
a refused upload sees its refusal rather than a dropped connection; every refusal carries
the error code, status and message S3 answers with. Large
files can be uploaded in parts, as the AWS CLI uploads them, every part but the last at
least 5 MiB as S3 requires, each part and the completion
held to the checksum the upload was created with, and the object given S3's composite or
full-object checksum of them, completed once however many
completions of the upload are sent, at once or as retries (each answered as the first while
the object is still the one it made), read back a part at a time,
parts copied from other objects,
and unfinished uploads listed, aborted, or cleaned up by `gc` once idle; `status` counts
them. Set `s3 = false` in the server config to turn it off. A newly created API key is also
shown as the S3 key pair, ready to paste. With wildcard DNS, setting `s3_host` also serves
each bucket at its own host name, as clients using virtual-hosted style address it. Jobs a
fleet hub places with their own registry token reach it too through the guest registry
proxy, holding no credential: `sccache` there takes bucket `job` with its area's alias as the
key prefix.

## [0.106.0] - 2026-11-05

### Added
Expand Down
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 13 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,20 @@ oci-client = { version = "0.18", default-features = false }
flate2 = "1"
# docker-hash: content hashing of a (Dockerfile, stage) for image-tag resolution
sha2 = "0.11"
# vk-tpm's SHA-1 PCR bank (TPM 2.0 keeps one for compatibility). RustCrypto, like sha2; already
# in the tree via russh.
# vk-tpm's SHA-1 PCR bank (TPM 2.0 keeps one for compatibility), and vk-registry's check of an
# S3 upload's x-amz-checksum-sha1. RustCrypto, like sha2; already in the tree via russh.
sha1 = "0.11"
# vk-registry: the MD5 an S3 object's ETag is, and the check of a Content-MD5. Already in the
# tree via russh.
md5 = "0.8"
# vk-registry: the check of an S3 upload's x-amz-checksum-crc32. Already in the tree via flate2.
crc32fast = "1.5"
# vk-registry: the check of an S3 upload's x-amz-checksum-crc32c and -crc64nvme, from its
# catalog. Already in the tree via lzma-rs.
crc = "3"
# vk-registry: the check of an S3 upload's x-amz-checksum-xxhash64, -xxhash3 and -xxhash128.
# Pure Rust, no dependencies of its own; XXH3 is too intricate to rewrite safely.
xxhash-rust = { version = "0.8", features = ["xxh64", "xxh3"] }
# vk-tpm: the TPM's entropy (TPM2_GetRandom, its seeds) from the OS. Already in the tree via rand.
getrandom = "0.4"
# vk-tpm: constant-time comparison of authorization values. Already in the tree via the
Expand Down
6 changes: 6 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

vk-registry's SigV4 tests use AWS's signing test suite, as vendored in awslabs/aws-c-auth
(tests/aws-signing-test-suite/v4), copied under vk-registry/src/s3/testdata/sigv4/:
https://github.com/awslabs/aws-c-auth/tree/3281f8692e6fd10562c4585a4dded5c16b322698/tests/aws-signing-test-suite/v4
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
Apache License 2.0; see vk-registry/src/s3/testdata/sigv4/LICENSE.

The variable expansion in vk-gitlab/src/spec.rs (`expand`) and vk-driver/src/node/jobs/vars.rs
is adapted from Go's os.Expand (src/os/env.go) and its tests, as gitlab-runner uses it:
https://github.com/golang/go/blob/go1.24.0/src/os/env.go
Expand Down
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,22 @@ with `read:files/<dir>/*` only reads it. Cached files expire under `vk-registry
retention like any other tag, unless their manifest keeps or expires them. Set
`webdav = false` in the server config to disable WebDAV.

The same plain-file area is served as S3 under `/s3/`, a bucket being a top-level directory
of `/dav/files/`, so `sccache`'s S3 backend, the AWS CLI and SDKs and other S3 clients can use
it. The access key is the registry credential — an API key, a hub token, or the shared bearer —
and the secret access key is the same string; with a shared Basic user, the user name and its
password. For `sccache`:

```bash
SCCACHE_BUCKET=sccache SCCACHE_ENDPOINT=https://<registry>/s3 SCCACHE_REGION=auto \
SCCACHE_S3_KEY_PREFIX=<dir> AWS_ACCESS_KEY_ID=$KEY AWS_SECRET_ACCESS_KEY=$KEY sccache …
```

Object keys follow the store's names (`A-Z a-z 0-9 . _ -` between slashes, at most 1024
bytes); objects are at most 4 GiB; presigned URLs are refused. Set `s3 = false` to disable
it. With wildcard DNS, `s3_host = "s3.example.com"` also serves each bucket virtual-hosted
style, as `https://<bucket>.s3.example.com/<key>`.

`vk registry put [--dir <dir>] [--ttl 7d | --keep] <file>...` stores files there, each once by
digest (`/dav/files/sha256/<hex>`) and, with `--dir`, by name (`/dav/files/<dir>/<name>`), and
`vk registry get <sha256:hex | dir/name>` fetches one back, checked against its digest;
Expand Down Expand Up @@ -883,7 +899,7 @@ See [`docs/registry-hub.md`](docs/registry-hub.md).
| --- | --- |
| `vk` | Host CLI, VMM, image builder, userspace network, compose runner, and GitLab executor. It embeds the default guest kernel and `vk-agent`. |
| `vk-agent` | Guest PID 1 and command server. It configures mounts, networking, hostname, shared directories, optional SSH, and host-driven execution over vsock. |
| `vk-registry` | Optional OCI-distribution server with a pull-through cache, a WebDAV view of the store with a plain-file area for compiler caches, and build-once locking. |
| `vk-registry` | Optional OCI-distribution server with a pull-through cache, a WebDAV view of the store with a plain-file area for compiler caches, also served as S3, and build-once locking. |
| `vk-hub` | Experimental hub for a fleet of `vk node` hosts, and a web UI for the VMs on this machine: `vk-hub local` serves it on loopback. See the [fleet design](docs/fleet-design.md) and [prototype reference](docs/fleet-prototype.md). |
| `vk-gitlab` | Experimental GitLab runner for a `vk-hub` fleet: takes jobs from GitLab and has the hub run each on a `vk node`. See [GitLab dispatch](docs/gitlab-dispatch.md). |
| `vk-runnerctl` | Optional root-side helper that adjusts GitLab runner concurrency within an administrator-configured range. |
Expand Down
19 changes: 15 additions & 4 deletions docs/gitlab-dispatch.md
Original file line number Diff line number Diff line change
Expand Up @@ -664,10 +664,21 @@ job and injects the job's token, never the node's credential. A job with no toke
proxy that refuses everything; so does every job a local gitlab-runner gives the node, which
under `"job"` reaches the registry only by its own means.

With a token, the proxy forwards the lock API (`/lock/`) and plain files (`/dav/files/`) as
well as `/v2/`; the registry enforces the token's grants. Under `/dav/files/` only GET,
HEAD, PROPFIND, PUT, MKCOL, DELETE and OPTIONS pass: MOVE and COPY would name the proxy in
their `Destination`. The job's steps find the proxy in `VK_REGISTRY` (`http://registry.vk`)
With a token, the proxy forwards the lock API (`/lock/`), plain files (`/dav/files/`) and their
S3 view (`/s3`) as well as `/v2/`; the registry enforces the token's grants. Under
`/dav/files/` only GET, HEAD, PROPFIND, PUT, MKCOL, DELETE and OPTIONS pass: MOVE and COPY
would name the proxy in their `Destination`. On `/s3`, the guest's own signature is replaced by
the token, so a job points `sccache` at its area with no key at all:

```sh
export SCCACHE_BUCKET=job SCCACHE_S3_KEY_PREFIX=<alias>/ SCCACHE_ENDPOINT=$VK_REGISTRY/s3
export SCCACHE_REGION=auto SCCACHE_S3_NO_CREDENTIALS=true
```

`job/<alias>` there stands for the area's prefix, as on `/dav/files/job/<alias>`
([4b](registry-hub.md#4b-registry-access-from-inside-a-job)); `SCCACHE_S3_NO_CREDENTIALS`
sends the requests unsigned, and dummy `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` work as
well. The job's steps find the proxy in `VK_REGISTRY` (`http://registry.vk`)
and their grants in `VK_REGISTRY_NAMESPACES`, space-separated `<prefix>=<rights>` with `r`,
`w` and `l` for read, write and lock. The proxy needs `net.mode = "switch"`, the only network
that serves `registry.vk`; under any other, a job gets neither the proxy nor these variables.
Expand Down
27 changes: 23 additions & 4 deletions docs/registry-hub.md
Original file line number Diff line number Diff line change
Expand Up @@ -632,8 +632,8 @@ though within them it can claim protection.

### 4b: registry access from inside a job

- **The proxy.** When it injects a job token, the credential proxy forwards `/lock/` and
`/dav/files/` as well as `/v2/`. With the node's credential it keeps refusing anything
- **The proxy.** When it injects a job token, the credential proxy forwards `/lock/`,
`/dav/files/` and the S3 view (`/s3`) as well as `/v2/`. With the node's credential it keeps refusing anything
outside `/v2/`, since that credential is not scoped. The proxy filters no namespace
itself: the registry enforces the token.
- It sets no response timeout of its own: `/lock/acquire` long-polls for up to an hour by
Expand Down Expand Up @@ -674,12 +674,21 @@ though within them it can claim protection.
(`name=job/<alias>/…:<key>`, decoded as the registry decodes it). The mapped URL goes
through the proxy's checks again. Any other path is forwarded as it is; `job/…` naming no
alias of the job is refused with 403 and not forwarded.
- On the S3 view, `/s3/job/<alias>/<key…>` is likewise the key below the area's prefix, and
`x-amz-copy-source: /job/<alias>/<key>` the same. A prefix `a/b/c` is bucket `a` and key
prefix `b/c/`. `/s3/job/<alias>` alone is the area as a bucket: its listings go to bucket
`a` with `b/c/` put before their `prefix`, `start-after`, `marker` and `key-marker` and
into their `continuation-token` (base64url of a key), so they stay in the area; when the
prefix has more than one component, only reads pass there. The guest's SigV4
`Authorization`, with dummy keys or none, is replaced by the token, as any other.
- No other query parameter is mapped: an OCI cross-repository mount's `from=job/<alias>/…`
reaches the registry as it is.
- Only requests are mapped. The registry answers with real names, an upload's `Location`
among them, which the proxy forwards unchanged, so a client continues on the real path.
A `PROPFIND`'s hrefs are mapped back to the alias, since a WebDAV client resolves a
listing against the root it asked for.
listing against the root it asked for, and so are the names in an S3 document answering
a request through an area — the bucket, keys, prefixes, markers, continuation tokens, a
`Location` and an error's `Resource` — and a created bucket's `Location`.
- No namespace's path may start with `job`. The hub refuses an alias while one stored
before that rule has such a path, and gives no job any alias until it moves.
- The hub sends a job's areas (`JobRegistry.areas`) only to a node announcing
Expand All @@ -694,7 +703,17 @@ though within them it can claim protection.
- **In-job tools.** task-rs takes `vk: http://registry.vk/job/task-cache` as its cache:
entries under the alias and lock names `job/task-cache/<namespace>:<key>`. sccache uses
`$VK_REGISTRY/dav/files/job/<alias>` as its WebDAV endpoint (the alias in the endpoint, not
in `key_prefix`, so it never creates `/dav/files/job/` itself). Neither holds a credential.
in `key_prefix`, so it never creates `/dav/files/job/` itself), or the S3 view:

```sh
SCCACHE_BUCKET=job SCCACHE_S3_KEY_PREFIX=<alias>/ SCCACHE_ENDPOINT=$VK_REGISTRY/s3 \
SCCACHE_REGION=auto SCCACHE_S3_NO_CREDENTIALS=true
```

`SCCACHE_S3_NO_CREDENTIALS` sends unsigned requests; dummy `AWS_ACCESS_KEY_ID` and
`AWS_SECRET_ACCESS_KEY` do as well, since the proxy drops the signature. Other S3 clients
list an area as the bucket `<alias>` at the endpoint `$VK_REGISTRY/s3/job`, path-style
(`aws --endpoint-url $VK_REGISTRY/s3/job s3 ls s3://<alias>/`). None holds a credential.

### 4c: pipeline caches and captures

Expand Down
6 changes: 3 additions & 3 deletions tests/gitlab-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
# Environment: VK_GITLAB_E2E_CACHE (default ~/.cache/vk-gitlab-e2e) holds the GitLab
# instance; GL_MEM (6G) and GL_CPUS (4) size its VM; GL_BOOT_TIMEOUT (1500 s). E2E_TOKENS=0
# runs the fleet without hub registry tokens: the registry not enrolled, the node's own
# credential for caches, and the `registry` and `pipeline_build` scenarios skipped.
# credential for caches, and the `registry`, `pipeline_build` and `registry_s3` scenarios skipped.
#
# Needs: KVM, curl, jq, git, openssl, ss, ip, shuf, network to Docker Hub; about 9 GiB of free RAM
# (GitLab 6 GiB, job VMs 1 GiB each) and 15 GiB of disk for the GitLab image and its state.
Expand All @@ -52,7 +52,7 @@ REPO=$(cd "$E2E/../.." && pwd)
# shellcheck source=gitlab/scenarios.sh
. "$E2E/scenarios.sh"

ALL_SCENARIOS=(basic scripts variables exit_codes artifacts cache registry pipeline_build services
ALL_SCENARIOS=(basic scripts variables exit_codes artifacts cache registry pipeline_build registry_s3 services
timeout cancel restart)

usage() {
Expand Down Expand Up @@ -210,7 +210,7 @@ pids=()
for s in "${SCENARIOS[@]}"; do
case $s in
restart) ;;
registry | pipeline_build)
registry | pipeline_build | registry_s3)
if [ -z "$VK_REGISTRY" ] || [ "$E2E_TOKENS" = 0 ]; then
echo "SKIP|needs a vk-registry taking hub tokens" >"$RUN/results/$s"
else
Expand Down
53 changes: 53 additions & 0 deletions tests/gitlab/scenarios.sh
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,59 @@ EOF
SC_DETAIL="built in $p1 ($ref), refused in $p2"
}

# A job reaches the S3 view through the guest proxy by an area's alias, the area three
# components deep (bucket e2e-s3, keys below e2e/<project>/): it writes, reads, lists and
# probes an object there unsigned, the proxy lending the job's token, and is refused another
# alias and a bucket its token does not cover. busybox wget sends neither PUT nor HEAD, so the
# requests go over nc. The token stays out of the trace.
sc_registry_s3() {
local ci p j
hub namespaces add "$REG_ID" e2e-s3 --path 'e2e-s3/{gitlab}/{project_id}' \
--alias s3area --grant 'rw:own project' >>"$LOGS/hub-cli.log" 2>&1 || {
bad "vk-hub namespaces add e2e-s3 failed"
return 1
}
ci=$({
ci_header
cat <<'EOF'
s3:
script:
- |
H=${VK_REGISTRY#http://}
HOST=${H%%:*} PORT=80
case $H in *:*) PORT=${H##*:} ;; esac
req() {
printf '%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %s\r\nConnection: close\r\n\r\n%s' \
"$1" "$2" "$H" "${#3}" "${3:-}" | nc "$HOST" "$PORT" | tr -d '\r'
}
code() { req "$@" | awk 'NR == 1 { print $2 }'; }
BODY=s3-probe-$CI_PIPELINE_ID
echo "put=$(code PUT /s3/job/s3area/probe "$BODY")"
echo "get=$(code GET /s3/job/s3area/probe)"
echo "get-body=$(req GET /s3/job/s3area/probe | sed '1,/^$/d')"
LIST=$(req GET '/s3/job/s3area?list-type=2')
echo "list=$(printf '%s\n' "$LIST" | awk 'NR == 1 { print $2 }')"
echo "list-key=$(printf '%s' "$LIST" | grep -c '<Key>probe</Key>')"
echo "list-name=$(printf '%s' "$LIST" | sed -n 's:.*<Name>\([^<]*\)</Name>.*:\1:p')"
echo "head=$(code HEAD /s3/job/s3area/probe)"
echo "head-length=$(req HEAD /s3/job/s3area/probe | sed -n 's/^[Cc]ontent-[Ll]ength: *//p')"
echo "put-nope=$(code PUT /s3/job/nope/x x)"
echo "put-images=$(code PUT /s3/images/x x)"
EOF
})
p=$(push_scenario registry_s3 <<<"$ci") || return 1
wait_pipeline "$p" success || return 1
j=$(job "$p" s3)
keep_job "$j"
local body=s3-probe-$p want
for want in put=200 get=200 "get-body=$body" list=200 list-key=1 list-name=s3area head=200 \
"head-length=${#body}" put-nope=403 put-images=403; do
grep -qE "${LINE}${want}\$" "$RUN/jobs/$j.log" || bad "job $j's trace lacks a line '$want'"
done
trace_lacks "$j" vkt_
SC_DETAIL="pipeline $p: an area's S3 alias written, read, listed and probed; others refused"
}

sc_services() {
local p j
p=$({
Expand Down
Loading
Loading