Added
-
feint run(#849): runs one command with a client whose cloud endpoint is
compiled in landing on this emulator, with no privilege, no network namespace
and no system mutation. It takes no hostname, and that is the safety
property: the mounted S3 doors come from the emulator's own report and each
door's cloud authority from the pack in this binary, so the only possible
targets are doors that exist. An operator typing a hostname is an operator
able to mistype it, and a mistyped cloud host is not intercepted but
resolved — the run leaves for a third party and looks like it worked. Every
other host is refused rather than tunnelled, the authority lives in a
directory the run creates and removes, the four variables are set on the child
alone, and credentials that are not this repository's public fakes are refused
because the emulator checks no signature. CLI surface 28.Proved with the client, not with curl: the published Scaleway provider 2.82.0
completes apply throughfeint runon the host network, with no sudo and
no namespace, and 139,264 identical bytes are read back from the local
byte store by sha256, followed by an empty second plan and a complete
teardown.TestScalewayTerraformStorageThroughFeintRunOnTheHostNetworkis
that witness, and it refuses to run inside a namespace, because a pass
obtained in one would prove the namespace's containment rather than the
command's.Two limits the measurement moved. The virtual-host form
<bucket>.<authority>
is intercepted as well as the bare one, since a path-style probe passes while
every bucket request a real client makes would be refused; the widening only
affects what is intercepted, as the transport still refuses a leading label
that is not a valid bucket name. AndAWS_CA_BUNDLEis stripped rather than
set, including from an inherited environment: the provider fails its apply
withunable to add custom RootCAs HTTPClient, has no WithTransportOptions
when it is present, andSSL_CERT_FILEalready covers every Go client. -
feint doctorreports leftover interception authorities (#849), and tells
a leftover from a run in flight by the owning PID each run records. A run in
progress legitimately owns such a directory, so a check that only reported
their existence would warn on every correct use. A leftover is a warning, not
a failure: it holds a public certificate in an owner-only directory, so it
leaks nothing and blocks nothing. -
Object Storage release groundwork (#850, #858): ordinary Exo bucket
creation/show/removal and native usage now use recorded default discovery
errors and the actual published byte inventory. The native inventory is
exoscale/v2.list-sos-buckets-usage, a refusal withdrawn: it answers
GET /v2/sos-buckets-usagefrom the same published bytes rather than a
catalogue,exo storage listdrives it (the client calls
ListSOSBucketsUsage), and it still answers 503 without--objectstore
because an inventory of an inventory that does not exist is not zero.
Scaleway Terraform 2.82.0
completes apply, empty plans, byte-store reopen, identical 122,880-byte GET,
destroy and explicit GC in a loopback-only namespace through scoped TLS
interception. This is a test harness, notfeint runor full-stack certification.
Neutral named byte checkpoints preserve multipart sessions and protect GC
references; coordinated CLI/control-plane/runtime reset remains unfinished. -
Persistent multipart, proved with real Exo/AWS clients (#856):
exo 1.95.1 multipart-uploads 6,340,608 bytes; AWS verifies assembled bytes,
resumes persisted parts after actual restart and completes another object.
Exo bucket removal aborts a real dangling session before deleting the bucket.
Private metadata v4 reads v1..v3; older binaries need a pre-upgrade whole-store
copy for rollback. Assembly uses the simple-PUT limit; retained parts and
assembly share the blob quota, and abort is not GC. Opaque SHA-256 part tags
are not generic ETags. The newer slice above adds normal Exo creation and
native usage; mixed per-key cloud errors and full Object Storage 1.0 remain
outside this proof. -
Measured Exo bulk deletion (#856): exo 1.95.1 deletes four actual keys;
AWS independently checks the empty inventory across restart and untouched
Scaleway bytes. DeleteObjects verifies transport checksums and closed XML
before one metadata transaction (1..1000 unversioned keys, 8 MiB XML).
Verbose/quiet results describe actual deletions. Blobs remain retained;
mixed per-key cloud errors and complete bucket-creation workflows remain
outside this measured slice. -
Measured Exo object listing and multi-range downloads (#850):
exo 1.95.1 downloads 73,728-byte and 6,340,608-byte binary objects with exact
byte/SHA-256 and listing-date proof before/after actual restart. AWS independently
decodes two one-entry ListObjectsV2 pages. Single-byte-range GETs serve actual
offsets/lengths without whole-object checksums on partial bytes.
Private metadata v3 persists publication dates, reads v1/v2 without rewriting
them and upgrades on mutation; older binaries cannot read v3. Listing pages
containing legacy undated objects are explicitly refused until overwrite.
Generic ETags and complete Exoscale bucket-creation workflows remain unsupported. -
Same-port synthetic S3 hosts, proved with Exo uploads (#850):
opt-inserve/start --s3-host-doorsretains the prefix doors and serves
declared provider/region HTTP authorities through a local non-forwarding
proxy. Exo 1.95.1 uploads binary bytes; AWS verifies bytes/SHA-256 before
and after actual restart. Native routes, browser/peer guards, quotas and
namespace separation remain intact. Exoscaleenv --s3sets dedicated-shell
proxy variables; explicitenv --s3 --unsetremoves them without restoring
prior values. Scaleway retains its measured prefix environment.
Status/doctor describe the hosts. S3 report schema is now 2 and the
CLI surface 27. Full Exoscale workflows, cloud bucket virtual hosts
and TLS/Terraform interception remain unsupported. -
Measured Exoscale S3 prefix incompatibility (#850):
conformance:s3:exo:endpointproves that exo 1.95.1 removes the configured
URL prefix from both bucket discovery and object upload. This listener
deliberately refuses the PUT; it does not certify a byte lifecycle.
Prefixed mounted doors remain proved with AWS CLI/scw, not exo. -
Opt-in, persisted simple S3 bytes on the existing port (#850):
serve/start --objectstore,--s3-doors,--objectstore-budget-mib
(1024 by default) and--s3-object-limit-mib(256 by default).
Declared provider/region prefixes preserve literal keys and separate
namespaces.restartpreserves the absolute root and limits; resource
snapshots and cleanup do not own these bytes. AWS CLI 2.32.17 proves
byte/checksum identity through the real process before and after restart.
Completeexolifecycles, ETag semantics, multipart and hardcoded
Terraform endpoints remain unsupported. -
Live S3 discovery, not an endpoint guessed while disabled (#850):
env --s3 [--s3-region],doctor --s3, explicit enabled/disabled/unknown
status, and independent/_feint/s3report schema 1. HTTP response
counts do not inflate control-plane SDK coverage or client evidence.
The additive CLI surface is version 26; existing exit codes and the
health schema stay unchanged. Ordinaryenv --unsetalso clears S3
endpoint variables offline. -
Measured private Scaleway bucket lifecycle (#850):
scw2.62.0
create/list/get/delete, alongside verified AWS CLI bytes, survives actual
process restart. Region XML, bounded transport checksums, persisted
Suspendedversioning, private canonical ACL and recordedNoSuchTagSet
are served; version histories, writable tags and public grants are refused.
S3 env endpoints omit the slash the SDK rejects; canonical bare bucket-list
roots are dispatched without redirects. Neutral private metadata version 2
reads version 1 and upgrades on mutation; older binaries cannot read it. -
An instance snapshot imports from Object Storage (#850, #262):
instance/v1/API.CreateSnapshottakes{bucket, key}and reads the object
through the door of its own region, where it was refused outright before. The
snapshot takes the object's size and carries no base volume; an absent object
is refused, as upstream refuses it; and with no byte store armed the refusal
names--objectstoreand--s3-doorsrather than the limits page. block/v1's
import reads through the same code, which closes the divergence #807 recorded
in its own words. A limit moved:docs/limits.mdsays what is now served
and that the real API's dialect for a missing object is still unmeasured. -
mise run vulncheck: govulncheck on demand against the pinned toolchain.
Not inprepush, and #865 says why: its verdict changes without a line of
this repository changing.
Fixed
feint runaccepted the fakesfeint envpublishes (#849): the sequence
both commands document — evalfeint env, thenfeint run— was refused by
its own binary, because the accepted list was a second hand-written copy of
the credentials the packs publish and had drifted from them by two characters
on one value and by a whole missing value on another. The list is derived from
the packs now, so the two cannot disagree again.- An imported snapshot answered an empty base volume, which the Scaleway
provider reads back asvolume_id "fr-par-1/"and treats as
forces replacement, churning the snapshot and the image cut from it on
every plan. It answers null, and a surveyed third-party stack now applies
whole with an empty second plan.
Proved against
The clients
| Client | Version | Pinned in | Drives, in CI |
|---|---|---|---|
scw
| 2.56.3 | .github/workflows/conformance.yml (SCW_VERSION)
| Scaleway |
| Terraform | 1.13.3 | .github/workflows/conformance.yml (TERRAFORM_VERSION)
| Exoscale, Outscale, Scaleway |
| OpenTofu | 1.12.5 | .github/workflows/conformance.yml (TOFU_VERSION)
| Exoscale, Outscale, Scaleway |
octl
| 0.0.32 | .github/workflows/conformance.yml (OCTL_VERSION)
| Outscale |
exo
| 1.95.6 | .github/workflows/conformance.yml (EXO_VERSION)
| Exoscale |
The Terraform providers
The client above is the engine; what answers this emulator is the provider.
Each row is one required_providers entry, read where it is written.
| Fixture or stack | Provider | Constraint | What that is worth | Applied in CI |
|---|---|---|---|---|
tools/conformance/faults
| outscale/outscale
| ~> 1.7
| constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
tools/conformance/outscale/terraform
| outscale/outscale
| ~> 1.7
| constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
tools/conformance/outscale/terraform-doorway
| outscale/outscale
| ~> 1.7
| constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
tools/conformance/scaleway/terraform
| scaleway/scaleway
| 2.83.0
| exact: the version that answered | yes |
examples/stacks/exoscale
| exoscale/exoscale
| 0.72.0
| exact: the version that answered | yes |
examples/stacks/exoscale
| hashicorp/aws
| 6.72.0
| exact: the version that answered | yes |
examples/stacks/outscale
| outscale/outscale
| ~> 1.7
| constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
examples/stacks/outscale/modules/net
| outscale/outscale
| ~> 1.7
| constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
examples/stacks/scaleway
| scaleway/scaleway
| 2.83.0
| exact: the version that answered | yes |
examples/quickstart/outscale
| outscale/outscale
| ~> 1.7
| constraint: resolved fresh on each run, so the version that answered is not knowable here | yes |
examples/quickstart/scaleway
| scaleway/scaleway
| 2.83.0
| exact: the version that answered | yes |
Read the third column narrowly, because it is the one a consumer pins against.
An exact constraint names the version that answered. A constraint is
resolved by terraform init -upgrade on the runner, every run, so the version
that answered is not knowable from this repository — it is a floor, not a
proof. Not pinned is not pinned: nothing here says which version ran, and
no number is invented to fill the cell.
Every stack under examples/stacks/ is applied on every pull request.
Generated from the conformance workflow and the fixtures at this tag.
A newer client is not known to work until the pin moves and the suite
passes on it: docs/clients.md says what each cell is worth.