Devsy
Developing in a Workspace

Secrets in a Workspace

Devsy can inject sensitive values into workspaces without placing plaintext credentials in devcontainer.json, command-line arguments, or ordinary dotenv files.

Secrets can come from two places:

  • Devsy-managed secrets — values owned by Devsy and stored in the operating system keyring or Devsy's encrypted local file.
  • External secret sources — values owned by another system, such as a SOPS-encrypted file. Devsy resolves these values when they are needed and does not import them into the local Devsy secret store.

Both use the same protected workspace delivery paths: lifecycle environment variables, in-memory files under /run/secrets, and supported build-secret mechanisms.

Devsy-Managed Secrets

With the default auto storage backend, Devsy stores sensitive values in your operating system's keyring when one is available:

  • macOS — Keychain
  • Windows — Credential Manager
  • Linux — Secret Service (libsecret / GNOME Keyring / KWallet)

When no keyring is available, or when the file backend is selected, Devsy stores values in an age-encrypted secrets.enc file in the Devsy config directory. Only non-sensitive metadata such as names and timestamps is written in plaintext. Devsy-managed secrets are scoped to the active context.

Creating a Secret

# Interactive input; the value is not echoed.
devsy secret set DB_PASSWORD

# Standard input is recommended for scripts.
printf '%s' "$MY_VALUE" | devsy secret set DB_PASSWORD --stdin

# Or read a value from a file.
devsy secret set TLS_KEY --from-file ./tls.key

Listing, Reading, and Deleting

devsy secret list
devsy secret get DB_PASSWORD
devsy secret delete DB_PASSWORD

devsy secret list never prints values. A value removed from the OS keyring outside Devsy is shown as orphaned.

External Secret Sources

An external secret source lets Devsy resolve a value at workspace startup without making Devsy a second source of truth for that value.

SOPS

Devsy supports SOPS-encrypted YAML, JSON, and dotenv files. Devsy uses the SOPS Go implementation; installing a sops executable is not required.

SOPS source documents use flat top-level key/value pairs in the initial implementation:

DATABASE_PASSWORD: ENC[...]
API_TOKEN: ENC[...]

Registering a Local SOPS Source

If the encrypted file is already available on the machine running Devsy, add a named source:

devsy secret source add sops project ./secrets.enc.yaml

Devsy validates that the file can be decrypted before saving the source. The configuration stores the source name, type, file path, and (when set via --format) the document format override only. Decrypted values are not copied into the keyring or Devsy's secrets.enc file.

List or remove locally registered sources with:

devsy secret source list
devsy secret source remove project

A source cannot be removed while context-level secret bindings still reference it.

Repository-Owned SOPS Sources

A repository can declare SOPS sources in either the root-level .devcontainer.json or .devcontainer/devcontainer.json layout under customizations.devsy.secretSources.

project/
├── .devcontainer/
│   └── devcontainer.json
└── secrets.enc.yaml

Example devcontainer.json:

{
  "name": "My Project",
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "customizations": {
    "devsy": {
      "secretSources": [
        {
          "name": "project",
          "type": "sops",
          "path": "./secrets.enc.yaml"
        }
      ],
      "secrets": [
        "sops:project/DATABASE_PASSWORD"
      ]
    }
  }
}

Repository source paths are resolved relative to the repository root. Devsy rejects paths, including symlink targets, that escape the repository root.

Repository-owned sources work with a local checkout:

devsy workspace up .

and with a remote Git source:

devsy workspace up https://github.com/acme/project

For a remote source Devsy first acquires repository data to read the requested Git revision, then reads customizations.devsy from the effective Dev Container configuration and the referenced encrypted SOPS files from that same revision.

Bootstrap Authentication for Private Repositories

Credentials needed to acquire a private repository must be available before Devsy can inspect repository-owned SOPS files.

For example, this is valid:

local Devsy secret / Git credential / SSH agent


        authenticate repository clone


     repository SOPS runtime secrets

A repository-owned SOPS secret cannot authenticate the clone of the same repository that contains it.

--git-token may reference a Devsy-managed secret or another external source that is already locally available before repository acquisition.

Referencing Secrets

An unqualified name continues to mean a Devsy-managed local secret:

DB_PASSWORD

An external source uses a source-qualified reference:

sops:project/DB_PASSWORD

Devsy does not search other sources if a reference cannot be resolved. Explicit source selection prevents one source from silently shadowing another.

Lifecycle Environment Variables

--secret is repeatable. By default, Devsy exposes the requested value as an environment variable to lifecycle commands:

devsy workspace up . --secret DB_PASSWORD
devsy workspace up . --secret sops:project/DATABASE_PASSWORD

Use target= to change the environment-variable name:

devsy workspace up . \
  --secret sops:project/DATABASE_PASSWORD,target=DB_PASSWORD

Mounted Secret Files

Use type=mount to write the secret to the existing in-memory secret mount:

devsy workspace up . \
  --secret sops:project/TLS_KEY,type=mount,target=tls.key

The value is available at:

/run/secrets/tls.key

Providers that cannot offer an in-memory secret mount reject type=mount with an error.

Build Secrets

Source-qualified references can also be used with Devsy's existing build-secret path:

devsy workspace up . --build-secret sops:project/NPM_TOKEN

The build secret ID is the secret key (NPM_TOKEN), not the complete source-qualified reference. Builds continue to consume it through the existing BuildKit secret mechanism, for example:

RUN --mount=type=secret,id=NPM_TOKEN ...

Attaching a Secret to a Context

Attach a locally available secret reference to the active context so it is injected on every workspace up:

devsy secret attach DB_PASSWORD
devsy secret attach sops:project/API_TOKEN

Detach it with:

devsy secret detach DB_PASSWORD
devsy secret detach sops:project/API_TOKEN

Devsy stores only the reference for an external secret. Repository-owned customizations.devsy can declare project-specific automatic bindings with its secrets list. If any requested or attached value cannot be resolved, workspace up fails rather than silently starting without it.

SOPS Credential Discovery

Devsy delegates key and KMS credential discovery to SOPS instead of creating a parallel credential system.

For age-encrypted files, normal SOPS mechanisms apply, including SOPS_AGE_KEY, SOPS_AGE_KEY_FILE, and the standard SOPS age-key location. For example:

export SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt"
devsy workspace up .

For AWS KMS, GCP KMS, Azure Key Vault, PGP, and other key services supported by SOPS, use the same credentials and key configuration you would use with SOPS itself.

How Secrets Are Protected

Devsy workspaces protect sensitive values by:

  • Decrypting SOPS sources in memory at workspace startup without persisting plaintext to disk
  • Injecting secrets directly as environment variables or memory-backed files under /run/secrets
  • Redacting known secret values from logs and terminal outputs
  • Excluding secret values from client-server transport and workspace metadata

Choosing a Devsy Storage Backend

For Devsy-managed values, use the supported backends:

  • keyring — the OS keyring (Keychain / Credential Manager / libsecret).
  • file — an age-encrypted secrets.enc stored alongside the Devsy config.
  • auto — use the keyring when available and otherwise fall back to file.

Set a persistent preference per context with:

devsy context set -o SECRETS_BACKEND=file

Or override it for one command with DEVSY_SECRETS_BACKEND.

The local file backend generates and manages an encryption key automatically. For stronger at-rest protection, set a passphrase with DEVSY_SECRETS_PASSPHRASE; the derived encryption key is then not stored on disk.

Managed Environment Variables

For non-sensitive configuration, devsy env stores managed environment variables in plaintext Devsy configuration:

devsy env set LOG_LEVEL=debug
devsy env set REGION --value us-east-1
devsy env list
devsy env get LOG_LEVEL
devsy env delete LOG_LEVEL

Inject them with:

devsy workspace up ... --env LOG_LEVEL --env REGION=AWS_REGION

Use devsy secret or an external secret source for sensitive values. --env is deliberately restricted to non-sensitive Devsy-managed values because that path is not the protected secret-delivery channel.

On this page