Class: Terret::Credentials
- Inherits:
-
Hames::Service
- Object
- Hames::Service
- Terret::Credentials
- Defined in:
- lib/terret/credentials.rb
Overview
ctx — plan §6.9. The one place a provider's secret is resolved, and its security point: every value it resolves is fed to the session scrubber (Sessions#register_scrubber), so a resolved credential can never reach the durable log even if a tool echoes it back into a result. That is what makes this more than a lookup table — it closes the loop the config-pattern redactor (docs/exec.md §6) leaves open, catching a secret by its exact bytes rather than by a shape a deployment had to name in advance.
Resolution order is ENV-first by convention (<PROVIDER>_API_KEY), then an
optional encrypted file store. ENV ALWAYS wins; the file is consulted only
when ENV is silent (unset or empty), and a file present with no master key
REFUSES rather than falling back to anything unprotected.
On-disk format (a deployment writes it; a trt credentials set CLI is
future work, plan §14 — only the format is promised here): JSON at the
configured file: path, mapping each provider name to
Base64.strict_encode64( iv(12 bytes) || auth_tag(16 bytes) || ciphertext )
each entry AES-256-GCM under a 32-byte master key. The master key is ENV
TERRET_CREDENTIALS_KEY, itself Base64 of exactly 32 bytes — generate one
with openssl rand -base64 32. Both the file and the key are optional: with
neither, ENV <PROVIDER>_API_KEY resolves on its own and the file store is
inert, which is the shipped default.
Deferred (plan §14): an OS-keychain backend, and the writer CLI above.
Defined Under Namespace
Classes: Error
Constant Summary collapse
- IV_LEN =
AES-GCM standard nonce
12- TAG_LEN =
AES-GCM authentication tag
16- KEY_LEN =
AES-256
32- MIN_SCRUB_LENGTH =
Below this an exact-string scrub would match far too much: the empty string inserts the token between every character, and a two-character value paints ordinary prose. A real resolved credential dwarfs this floor, so a value under it is still resolved and returned — it just does not become an active scrub pattern (fail-safe: never corrupt the log to chase a value too short to be a secret worth catching by its bytes).
8- REPLACEMENT =
"[REDACTED]"
Instance Method Summary collapse
-
#reconfigure(_config) ⇒ Object
the file path is read per resolve.
-
#resolve(provider) ⇒ Object
The credential for a provider by name, or nil.
- #start(ctx) ⇒ Object
Instance Method Details
#reconfigure(_config) ⇒ Object
the file path is read per resolve
68 |
# File 'lib/terret/credentials.rb', line 68 def reconfigure(_config); end |
#resolve(provider) ⇒ Object
The credential for a provider by name, or nil. ENV wins; then the file store when configured. A non-trivial resolved value is registered as an exact-string scrub pattern before it is returned, so anything that later echoes it into the log is caught.
74 75 76 77 78 79 80 |
# File 'lib/terret/credentials.rb', line 74 def resolve(provider) name = provider.to_s env = ENV["#{env_name(name)}_API_KEY"] value = (env unless env.nil? || env.empty?) || from_file(name) remember(value) if value value end |
#start(ctx) ⇒ Object
59 60 61 62 63 64 65 66 |
# File 'lib/terret/credentials.rb', line 59 def start(ctx) @secrets = [] @mutex = Mutex.new # ONE scrubber over the growing set rather than a fresh registration per # resolve: re-resolving a provider must not stack duplicate scrubbers, and # a scrubber reaches every append whether it was registered early or late. ctx[:sessions].register_scrubber(method(:scrub)) end |