Loading
feat(config): add StorageConfig proto and startup validation (S06 Step 10)
What
Adds the StorageConfig proto message and all sub-messages, plus the Go runtime view and startup cross-field validation. This is Step 10 of the Storage Layer (S06) plan, sibling-parallel and gating the driver-adjust steps (16, 17, 20) that construct typed drivers.
- Proto (
proto/artifactregistry/config/v1/config.proto, regeneratedconfig.pb.go):StorageConfig+S3Config,GCSConfig,CloudFrontConfig,CloudCDNConfig,URLCacheConfigand their credential/encryption/multipart sub-messages, wired intoConfigas field 8. Backend is aoneof(s3|gcs) with(buf.validate.oneof).required = true. CDN middleware (cloudfront|cloud_cdn) andurl_cacheare optional. - Delivery mode: instance-default
delivery_modeenum (DELIVERY_MODE_REDIRECT/DELIVERY_MODE_PROXY) consumed byBlobStore.OpenBlob's two-axis resolution;DELIVERY_MODE_UNSPECIFIED(proto zero value) is rejected at startup vianot_in: [0]. - Runtime view + validation (
internal/config/storage.go): proto → typed Go struct conversion with size/duration parsing, and Go-side cross-field validation at startup (single-backend required, CDN/backend pairing — CloudFront⇒S3, Cloud CDN⇒GCS — at-most-one-CDN,cloudfront.aws_regionrequired whenip_filtered_by="awsregion", S3chunk_size5 MB–5 GB clamp, GCS 256 KiB alignment).
Why this shape
- Cross-field invariants are enforced in Go at startup rather than in protovalidate, per the spec's "Configuration" section — they span sibling fields and parsed values that CEL cannot express cleanly.
- The
TLSConfig tlsfield was dropped fromS3Config(field 20) andGCSConfig(field 10): the ported S3 v2 driver's TLS surface is fully expressed bytls_modeand the ported GCS driver has no TLS config, so the structured message had no consumer on either backend. Both tags are left reserved-in-comment; the sharedTLSConfigmessage is retained for future consumers (Redis, HTTP upstreams, the HTTP listener).
References
- Plan:
docs/plans/2026-05-15-storage-layer.md— Step 10 (StorageConfig proto). Plan MR merged onmain. - Spec:
docs/specs/S06-storage-layer.md— "Configuration" section + acceptance criteria. - ADRs: ADR-005 (artifact delivery mode), ADR-013 (storage backend / CDN pairing), ADR-008 (content-addressable storage;
root_directorydefault).
Tests
internal/config/storage_test.go — table-driven, run in go_unittests:
- Happy-path load of S3 and GCS configs through
config.Load(size→int64, duration→time.Duration, enum parsing), plus the absent-block no-op. - Validation rejections: missing backend, duplicate backend, CDN/backend mismatch, multiple CDN, missing
cloudfront.aws_region, invalid duration/size strings, S3 chunk-size bounds, GCS chunk-size alignment,DELIVERY_MODE_UNSPECIFIED/unknown enum.
Acceptance
-
buf generateclean; YAML fixtures load through buf-protoyaml; validation rejects missing/double/mismatched backend, bad duration/size, andDELIVERY_MODE_UNSPECIFIED.
Related to #159 (closed)