NativeLink

Oracle Cloud (OCI) Object Storage

Back the cache with OCI Object Storage through its S3 Compatibility API: Customer Secret Keys, the two adjustments the store makes for you, and what has actually been verified.

Who this is for: anyone running NativeLink on Oracle Cloud who wants the durable tier to be an OCI bucket. What you'll have at the end: a bucket-backed CAS and Action Cache authenticated with a Customer Secret Key. Time: thirty minutes, most of it namespace and policy setup.

Before you start

A config file you can edit (see Configuration), and an OCI tenancy you can create a bucket in.

OCI is one provider value of the same cloud object store used by S3 and compatible, GCS and Azure Blob: six providers over one store type, sharing the same multipart, retry and streaming code paths.

How it works

OCI Object Storage exposes an S3 Compatibility API, and the oci provider is a thin adapter pointing the S3 store at it. Two OCI-specific adjustments are applied automatically, and you do not configure either:

  • Path-style addressing. OCI requires endpoint/bucket/key rather than virtual-hosted bucket.endpoint/key URLs. The endpoint is derived as https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com.
  • Checksums downgraded to "when required". The AWS SDK otherwise adds a default trailing checksum that forces Content-Encoding: aws-chunked, which OCI rejects with 501 NotImplemented: AWS chunked encoding not supported. Without the downgrade, small single-PUT objects (notably Action Cache entries) fail.
OciStore

Before you start

You need three things.

A bucket. Create one in the Console under Storage → Buckets, or with oci os bucket create. Note its region, for example ap-mumbai-1.

Your Object Storage namespace. A tenancy-wide identifier shown under Tenancy details, or from oci os ns get. It goes into the derived endpoint.

A Customer Secret Key. See below.

Authentication

The S3 Compatibility API authenticates with Customer Secret Keys, a static access-key and secret-key pair used as access_key_id and secret_access_key, signed with AWS SigV4.

Generate one in the Console under Profile → User settings → Customer secret keys → Generate secret key. The secret is shown only once at generation time, so copy it immediately; the access key stays listed in the table and can be copied whenever you like. OCI has no way to retrieve a secret after generation, so if you lose it you rotate rather than recover.

Grant the associated user read and write on the bucket with a least-privilege policy:

Allow group <your-group> to manage object-family in compartment <compartment> where target.bucket.name='<bucket>'

Supply both keys through environment variables and reference them with ${VAR} rather than pasting them into the config; see The config file.

The recipe

A minimal CAS and Action Cache sharing one bucket, segmented by key_prefix:

stores: [
  {
    name: "CAS_MAIN_STORE",
    experimental_cloud_object_store: {
      provider: "oci",
      namespace: "storagenamespace",
      region: "ap-mumbai-1",
      bucket: "nativelink-cas",
      access_key_id: "${OCI_ACCESS_KEY_ID}",
      secret_access_key: "${OCI_SECRET_ACCESS_KEY}",
      key_prefix: "cas/",
      retry: { max_retries: 6, delay: 0.3, jitter: 0.5 },
    },
  },
  {
    name: "AC_MAIN_STORE",
    experimental_cloud_object_store: {
      provider: "oci",
      namespace: "storagenamespace",
      region: "ap-mumbai-1",
      bucket: "nativelink-cas",
      access_key_id: "${OCI_ACCESS_KEY_ID}",
      secret_access_key: "${OCI_SECRET_ACCESS_KEY}",
      key_prefix: "ac/",
      retry: { max_retries: 6, delay: 0.3, jitter: 0.5 },
    },
  },
],
oci_backend.json5

That is the smallest thing that works, not the thing to run. In production, wrap the CAS in verify for integrity and front it with a fast_slow filesystem tier to cut round trips, exactly as for AWS. Compose stores has the shapes.

Fields

FieldRequiredWhat it is
namespaceyesObject Storage namespace; used to derive the endpoint
regionyesOCI region id, for example ap-mumbai-1; also the SigV4 signing region
bucketyesTarget bucket
access_key_idnoCustomer Secret Key access key; if either key is unset the store falls back to the AWS default credential chain, which reads AWS_* names, not OCI ones
secret_access_keynoCustomer Secret Key secret
key_prefix, retry, …noThe shared cloud object options
ExperimentalOciSpec

OCI also accepts us-east-1 as a region value to target the tenancy home region, which is occasionally useful when a tool insists on an AWS region name.

Steps

  1. Create the bucket and note its region and your tenancy's Object Storage namespace.

  2. Generate a Customer Secret Key and copy the secret immediately, because it is shown once.

  3. Apply a least-privilege policy scoped to that bucket, and export both keys into the process environment.

  4. Add a lifecycle rule aborting incomplete multipart uploads after a few days as a backstop.

  5. Add the stores with distinct key_prefix values, then run a build twice.

You did it right if

  • Objects appear under both cas/ and ac/ in the bucket during the first build.
  • The second build is a cache hit, which proves the Action Cache round trip works. That is the path the checksum adjustment exists for.
  • A large artifact uploads and downloads intact, which exercises multipart.
  • No incomplete multipart uploads accumulate between builds.

Operational notes

Reap incomplete multipart uploads. When a multipart upload fails mid-flight the store issues AbortMultipartUpload to clean up, and OCI honors both ListMultipartUploads and AbortMultipartUpload. A process killed before it can abort still leaves orphaned parts, which is what the lifecycle rule is for.

Status. This backend lives under experimental_cloud_object_store. When it was added, its core paths (read, write, existence checks, ranged reads, multipart and integrity) were verified against live OCI, including an end-to-end Bazel remote cache round trip, a 2 GiB multipart upload of roughly 400 parts with full byte verification, multipart abort and cleanup, and 200-way concurrent load. It has not been benchmarked at sustained production scale or duration.

When it doesn't work

NextCompose stores

The verify wrapper and the fast_slow tier that turn this into something you'd run in production.

SidewaysS3 and compatible

The shared cloud object options (retry, expiry, buffering) documented in full.

On this page