sops

The atago project wrote these specs on its own initiative and runs them in its own CI, to exercise atago against a real program. They are not sops’s official test suite, and the sops project is not affiliated with atago.

Summary #

1 suite · 7 scenarios

Contents #

sops + age (secrets encryption) #

sops encrypts the values in a structured file while leaving its keys readable, so a secrets file stays reviewable in a pull request while its contents stay secret.

That split is the contract pinned here: after encryption the structure is still legible and every value is hidden; after decryption the values come back; and a single field can be extracted without decrypting the rest.

The negative guarantees carry equal weight. The wrong key must not decrypt. And flipping one byte of the ciphertext must fail the message authentication check rather than yielding subtly wrong plaintext — the integrity property that separates an encrypted file from an obfuscated one. A regex scoping which keys get encrypted is checked too, since a misconfigured scope is how secrets end up committed in the clear.

Source: test/e2e/thirdparty/sops/sops.atago.yaml

Scenario: version prints a semantic version offline #

only when sops --version --disable-version-check succeeds

When #

sops --version --disable-version-check

Then #

  • exit code is 0
  • stdout matches /sops [0-9]+\.[0-9]+\.[0-9]+/

Scenario: encryption hides values, keeps keys, and records metadata #

only when command -v sops && command -v age-keygen succeeds

Given #

  • Fixture file secrets.yaml is created.

Inputs #

Fixture secrets.yaml:

database:
  password: hunter2
  host: db.internal
region: us-west-1

When #

age-keygen -o key.txt
age-keygen -y key.txt
# capture ${recipient} from stdout
sops encrypt --age ${recipient} secrets.yaml

Then #

  • after age-keygen -o key.txt:
    • exit code is 0
  • after sops encrypt --age ${recipient} secrets.yaml:
    • exit code is 0
    • stdout contains password:, host:, ENC[AES256_GCM, sops:, mac:
    • stdout does not contain hunter2, db.internal

Scenario: encrypt then decrypt recovers the original values #

only when command -v sops && command -v age-keygen succeeds

Given #

  • Fixture file secrets.yaml is created.
  • Environment variables are set: SOPS_AGE_KEY_FILE.

Inputs #

Fixture secrets.yaml:

database:
  password: hunter2
  host: db.internal
region: us-west-1

When #

age-keygen -o key.txt
age-keygen -y key.txt
# capture ${recipient} from stdout
sops encrypt --age ${recipient} --output secrets.enc.yaml secrets.yaml
sops decrypt secrets.enc.yaml

Then #

  • after sops encrypt --age ${recipient} --output secrets.enc.yaml secrets.yaml:
    • exit code is 0
  • after sops decrypt secrets.enc.yaml:
    • exit code is 0
    • stdout contains password: hunter2, host: db.internal, region: us-west-1

Scenario: extract returns a single decrypted value exactly #

only when command -v sops && command -v age-keygen succeeds

Given #

  • Fixture file secrets.yaml is created.
  • Environment variables are set: SOPS_AGE_KEY_FILE.

Inputs #

Fixture secrets.yaml:

database:
  password: hunter2
  host: db.internal
region: us-west-1

When #

age-keygen -o key.txt
age-keygen -y key.txt
# capture ${recipient} from stdout
sops encrypt --age ${recipient} --output secrets.enc.yaml secrets.yaml
sops decrypt --extract '["region"]' secrets.enc.yaml

Then #

  • after sops encrypt --age ${recipient} --output secrets.enc.yaml secrets.yaml:
    • exit code is 0
  • after sops decrypt --extract '["region"]' secrets.enc.yaml:
    • exit code is 0
    • stdout equals an exact value

Scenario: decrypting with the wrong key fails #

only when command -v sops && command -v age-keygen succeeds

Given #

  • Fixture file secrets.yaml is created.
  • Environment variables are set: SOPS_AGE_KEY_FILE.

Inputs #

Fixture secrets.yaml:

token: changeme

When #

age-keygen -o key.txt
age-keygen -y key.txt
# capture ${recipient} from stdout
sops encrypt --age ${recipient} --output secrets.enc.yaml secrets.yaml
age-keygen -o other.txt
sops decrypt secrets.enc.yaml

Then #

  • after sops encrypt --age ${recipient} --output secrets.enc.yaml secrets.yaml:
    • exit code is 0
  • after age-keygen -o other.txt:
    • exit code is 0
  • after sops decrypt secrets.enc.yaml:
    • exit code is 128
    • stderr contains Failed to get the data key

Scenario: a tampered ciphertext fails the MAC #

only when command -v sops && command -v age-keygen succeeds

Given #

  • Fixture file secrets.yaml is created.
  • Environment variables are set: SOPS_AGE_KEY_FILE.

Inputs #

Fixture secrets.yaml:

token: changeme

When #

age-keygen -o key.txt
age-keygen -y key.txt
# capture ${recipient} from stdout
sops encrypt --age ${recipient} --output secrets.enc.yaml secrets.yaml
sed '0,/data:/ s/data:\([A-Za-z0-9]\)/data:Z/' secrets.enc.yaml > tampered.yaml
sops decrypt tampered.yaml

Then #

  • after sops encrypt --age ${recipient} --output secrets.enc.yaml secrets.yaml:
    • exit code is 0
  • after sed '0,/data:/ s/data:\([A-Za-z0-9]\)/data:Z/' secrets.enc.yaml > tampered.yaml:
    • exit code is 0
  • after sops decrypt tampered.yaml:
    • exit code is 25
    • stderr contains message authentication failed

Scenario: an encrypted-regex scopes which keys are encrypted #

only when command -v sops && command -v age-keygen succeeds

Given #

  • Fixture file secrets.yaml is created.

Inputs #

Fixture secrets.yaml:

database:
  password: hunter2
  host: db.internal
region: us-west-1

When #

age-keygen -o key.txt
age-keygen -y key.txt
# capture ${recipient} from stdout
sops encrypt --age ${recipient} --encrypted-regex '^password$' secrets.yaml

Then #

  • after sops encrypt --age ${recipient} --encrypted-regex '^password$' secrets.yaml:
    • exit code is 0
    • stdout contains host: db.internal, region: us-west-1, password: ENC[AES256_GCM
    • stdout does not contain password: hunter2