LinuxSecretToolResolver Default { get; }
Source
Gets the production resolver that trusts /usr/bin/secret-tool
, then /bin/secret-tool
.
LocalSecrets store that delegates to the current operating system's user secret facility when available.
macOS uses an entitlement-free Security.framework SecItem
v2 Keychain namespace with retained legacy-record migration diagnostics, Windows uses current-user Credential Manager generic credentials, Linux uses Secret Service through secret-tool
, and unsupported sessions return display-safe diagnostics.
IAppSurfaceLocalSecretStore CreateInnerStoreForTests(AppSurfaceLocalSecretsOptions options, LinuxSecretToolResolver linuxSecretToolResolver, LocalSecretsPlatform? platformOverride = null)
Creates the platform-specific inner store with deterministic platform selection for tests.
options
linuxSecretToolResolver
platformOverride
The store selected for the requested platform and options.
Resolves the Linux secret-tool
executable from AppSurface-trusted defaults or an explicit absolute override.
The resolver is the trust boundary for Linux Secret Service command execution. It intentionally ignores arbitrary PATH
matches for command selection and reports them only as diagnostic context so package consumers do not accidentally execute a spoofed secret-tool
binary.
LinuxSecretToolResolution Resolve(string? overridePath)
Resolves the executable path that the Linux platform store may launch.
overridePath
AppSurfaceLocalSecretsOptions.LinuxSecretToolPath
or the CLI --secret-tool-path
option. Overrides must be absolute executable files. A successful resolution with a trusted executable path, or a failed resolution containing a display-safe diagnostic that explains why command execution is blocked.
Passing null
uses the trusted default candidates only. Passing an empty, relative, missing, directory, or non-executable override fails before any process is launched.
LinuxSecretToolResolution UnsupportedPlatformOverride(string overridePath)
Creates the diagnostic result used when a Linux-only override is configured on a non-Linux platform.
overridePath
A failed resolution instructing callers to remove the Linux-only override.
LinuxSecretToolResolver Default { get; }
Source
Gets the production resolver that trusts /usr/bin/secret-tool
, then /bin/secret-tool
.
Immutable outcome from resolving the Linux secret-tool
command path.
Succeeded
true
when Path
contains a command path that may be launched. Path
null
for failed resolutions. Status
Diagnostic
null
when resolution succeeds.
Callers should use Found(string)
and Failed(LocalSecretResultStatus, AppSurfaceLocalSecretDiagnostic)
so success results never carry diagnostics and failed results always carry the user-facing cause/fix guidance.
LinuxSecretToolResolution Found(string path)
Creates a successful resolution for a trusted executable path.
path
A resolution with Succeeded
set and no diagnostic.
LinuxSecretToolResolution Failed(LocalSecretResultStatus status, AppSurfaceLocalSecretDiagnostic diagnostic)
Creates a failed resolution with the status and diagnostic callers should surface.
status
diagnostic
A resolution with no executable path and Succeeded
unset.
AppSurfaceLocalSecretResult ReadStoredValue(AppSurfaceLocalSecretIdentity identity)
Reads one raw platform-stored value without applying indexed-store policy.
identity
LocalSecretResultStatus.Found
with the stored secret value when the value exists, LocalSecretResultStatus.Missing
when the platform confirms absence, or a terminal failure such as LocalSecretResultStatus.Locked
, LocalSecretResultStatus.Unavailable
, LocalSecretResultStatus.UnsupportedPlatform
, or LocalSecretResultStatus.ProviderFailed
when the platform cannot safely answer. List
depends on these statuses to distinguish stale indexed names from stores it could not verify.
AppSurfaceLocalSecretResult WriteStoredValue(AppSurfaceLocalSecretIdentity identity, string value)
Writes one raw platform-stored value without applying indexed-store policy.
identity
value
LocalSecretResultStatus.Found
with no display value when the platform write succeeds, or a terminal failure when the platform is locked, unavailable, unsupported, or rejects the write. Set
and index repair only report success after this method succeeds for both the value and any required index write.
AppSurfaceLocalSecretResult DeleteStoredValue(AppSurfaceLocalSecretIdentity identity)
Deletes one raw platform-stored value without applying indexed-store policy.
identity
LocalSecretResultStatus.Found
when the platform deleted an existing value, LocalSecretResultStatus.Missing
when the platform confirms absence, or a terminal failure when the platform cannot safely delete or confirm absence. Delete
uses the result together with an index read to decide whether to remove a stale indexed name, preserve a confirmed missing result, or fail closed.
AppSurfaceLocalSecretResult DoctorStore(string applicationName, string environment, string? keyPrefix)
Verifies raw platform store availability for a namespace.
applicationName
environment
keyPrefix
A display-safe readiness result. Implementations should exercise raw platform read/write/delete behavior without adding probe names to the user-visible index and should propagate locked, unavailable, unsupported, or provider failures so CLI diagnostics remain fail-closed.
AppSurfaceLocalSecretResult MapCommandFailure(PlatformSecretCommandResult result, string operation)
Maps a failed platform command result into the LocalSecrets diagnostic contract.
result
operation
get
or delete
.
A retryable not-found result classified as LocalSecretResultStatus.Locked
for real locked-store process output, or LocalSecretResultStatus.Unavailable
for timeouts, startup failures, and other process failures.
Only PlatformSecretCommandResultKind.ProcessExited
carries real platform process output that can prove a locked or denied user secret store. Synthetic PlatformSecretCommandResultKind.TimedOut
and PlatformSecretCommandResultKind.StartFailed
results must remain LocalSecretResultStatus.Unavailable
and use redacted cause text, even when the underlying exception message contains words such as locked
or denied
. Custom internal runners should use PlatformSecretCommandResult.FromProcess(int, string, string)
only after a platform command exits, and should keep command paths, arguments, logical values, absolute paths, and secret values out of AppSurfaceLocalSecretDiagnostic
provenance fields.
string BuildCommandFailureCause(PlatformSecretCommandResult result, string operation)
Builds the display-safe diagnostic cause for a failed platform command.
Real process exits report only the exit code because platform stderr can contain provider-specific text. Synthetic startup failures report sanitized exception provenance prepared by PlatformSecretCommandResult.StartFailed(Exception)
; if an internal runner constructs a startup failure without detail, the cause uses a stable fallback instead of rendering empty punctuation.
Captures display-safe output and provenance for one platform secret command attempt.
PlatformSecretCommandResult FromProcess(int exitCode, string output, string error)
Creates a result from a platform process that started and exited.
exitCode
output
error
A process-exited command result.
PlatformSecretCommandResult StartFailed(Exception exception)
Creates the synthetic result used when the platform command cannot be started.
exception
A display-safe startup failure result.
int ExitCode { get; }
Source
Gets the process exit code or the synthetic failure code for runner-level failures.
string Output { get; }
Source
Gets the trimmed standard output for process results.
string Error { get; }
Source
Gets standard error or display-safe synthetic failure details.
PlatformSecretCommandResultKind Kind { get; }
Source
Gets the result provenance used by platform status mapping.
PlatformSecretCommandResult TimedOut { get; }
Source
Gets the synthetic result used when the platform command exceeds the timeout.
Describes a local secret list operation.
Status
Keys
Diagnostic
Source
AppSurfaceLocalSecretListResult Found(IEnumerable<string> keys, string source)
Creates a successful list result.
keys
source
A list result.
AppSurfaceLocalSecretListResult Failed(LocalSecretResultStatus status, AppSurfaceLocalSecretDiagnostic diagnostic, string source)
Creates a non-success list result.
status
diagnostic
source
A list result.
Registers the AppSurface LocalSecrets provider and supporting services.
Add this module only when the application wants fail-closed local secret posture. Environment variables keep the highest precedence, LocalSecrets sits above file configuration, and only true missing local secrets fall through.
void ConfigureServices(StartupContext context, IServiceCollection services)
Registers LocalSecrets services.
context
services
Configures the AppSurface LocalSecrets provider.
Defaults are intentionally fail-closed: LocalSecrets is development-only, claims keys once registered, and reports local store failures as terminal diagnostics instead of falling through to lower-priority file configuration.
LocalSecretsPostureMode Posture { get; set; }
Source
Gets or sets the posture mode for local secret resolution.
string? ApplicationName { get; set; }
Source
Gets or sets the application identity used in the platform store namespace.
Leave unset to infer an identity from the entry assembly or current directory. Override this when multiple apps share a binary name or when command-line workflows need a stable package-independent identity.
string? KeyPrefix { get; set; }
Source
Gets or sets an optional namespace prefix applied before the AppSurface config key.
string DocsHint { get; set; }
Source
Gets or sets the documentation hint emitted in local secret diagnostics.
string? LinuxSecretToolPath { get; set; }
Source
Gets or sets an explicit Linux secret-tool
executable path for nonstandard trusted installs.
Leave unset to use AppSurface's trusted Linux system candidates only: /usr/bin/secret-tool
, then /bin/secret-tool
. Set this only when the binary is trusted and verified with a command such as test -x /absolute/path/to/secret-tool
. Relative, empty, missing, directory, and non-executable paths are rejected. This option is Linux-only; macOS and Windows use their native credential stores.
bool FailClosedOnStoreFailure { get; set; }
Source
Gets or sets a value indicating whether local store failures stop lower-priority provider resolution.
Keep the default enabled for secret posture. Disabling this escape hatch makes unavailable stores behave like missing values and can mask secrets from files.
ISet<string> DevelopmentEnvironmentNames { get; }
Source
Gets or sets development-like environment names accepted by LocalSecretsPostureMode.DevelopmentOnly
.
Identifies one local secret across application, environment, prefix, and AppSurface config key.
ApplicationName
Environment
KeyPrefix
Key
StorageName
Describes typed LocalSecrets provider resolution before it is adapted to ForgeTrust.AppSurface.Config.IConfigProvider
.
T
Status
Value
Status
is LocalSecretResultStatus.Found
.Diagnostic
Source
AppSurfaceLocalSecretResolution<T> Found(T? value, string source)
Creates a found resolution.
value
source
A found resolution.
AppSurfaceLocalSecretResolution<T> NotFound(LocalSecretResultStatus status, AppSurfaceLocalSecretDiagnostic diagnostic, string source)
Creates a non-found resolution with a display-safe diagnostic.
status
diagnostic
source
A non-found resolution.
Describes one value-safe local-secret migration outcome.
Key
Action
Status
Diagnostic
Provides display-safe text for AppSurfaceLocalSecretMigrationAction
values.
string ToDisplayString(this AppSurfaceLocalSecretMigrationAction action)
Returns the stable text rendered by the LocalSecrets migration command.
action
The stable action text, or the enum fallback text for an action introduced by a newer implementation.
Describes migration of one LocalSecrets namespace without exposing secret values.
Status
Rows
Diagnostic
Source
AppSurfaceLocalSecretMigrationResult Completed(IEnumerable<AppSurfaceLocalSecretMigrationRow> rows, string source)
Creates a completed migration result.
rows
source
The migration result.
AppSurfaceLocalSecretMigrationResult FailedToStart(LocalSecretResultStatus status, AppSurfaceLocalSecretDiagnostic diagnostic, string source)
Creates a migration result that could not start safely.
status
diagnostic
source
The failed migration result.
int Migrated { get; }
Source
Gets the number of records copied into current storage.
int AlreadyV2 { get; }
Source
Gets the number of records already present in current storage.
int Failed { get; }
Source
Gets the number of records that could not be migrated.
Supports an explicit, value-safe migration from a legacy LocalSecrets namespace to its current storage format.
This optional capability is implemented only by stores that have retained readable legacy records. It never performs migration during configuration resolution: callers must invoke it deliberately and handle the returned per-key status without rendering secret values.
AppSurfaceLocalSecretMigrationResult Migrate(string applicationName, string environment, string? keyPrefix)
Copies currently readable legacy records into the current storage format for one normalized namespace.
applicationName
environment
keyPrefix
A value-safe migration summary.
Describes the result of a local secret store operation.
Status
Value
Status
is LocalSecretResultStatus.Found
.Diagnostic
Source
AppSurfaceLocalSecretResult Found(string value, string source)
Creates a found result.
value
source
A found result.
AppSurfaceLocalSecretResult Missing(string source)
Creates a missing result that may fall through to lower-priority providers.
source
A missing result.
AppSurfaceLocalSecretResult NotFound(LocalSecretResultStatus status, AppSurfaceLocalSecretDiagnostic diagnostic, string source)
Creates a non-found result with a display-safe diagnostic.
status
diagnostic
source
A non-found result.
Implements the macOS v2 write-forward bridge while preserving v1 as a read-only recovery source.
V2 uses SecItem
without a data-protection attribute, access group, or custom ACL. This intentionally targets the entitlement-free file-based Keychain configuration proven by the macOS feasibility spike. The v1 store remains available only to identify records that require explicit operator migration.
Describes an immutable file-based macOS SecItem
generic-password identity.
Describes the status and optional raw value returned by a macOS SecItem
read.
Isolates native macOS Keychain request construction for deterministic compatibility tests.
MacOsSecItemReadResult Read(MacOsSecItemQuery query)
Reads the raw value for a generic-password query
.
query
The raw OSStatus and optional copied value. MacOsV2CompatibilityLocalSecretStore
maps OSStatus through its local-secret status mapping; a success status with null data is treated as a fail-closed provider error.
int Exists(MacOsSecItemQuery query)
Checks whether a generic-password query
exists without requesting its value data.
query
The raw OSStatus, which the v2 store maps through its local-secret status mapping.
int Add(MacOsSecItemQuery query, byte[] value)
Adds a generic-password value
under query
without overwriting a record.
query
value
The raw OSStatus, which the v2 store maps through its local-secret status mapping. Existing records must return errSecDuplicateItem
so MacOsV2CompatibilityLocalSecretStore
can route the write to Update
.
int Update(MacOsSecItemQuery query, byte[] value)
Replaces the value for an existing generic-password query
.
query
value
The raw OSStatus, which the v2 store maps through its local-secret status mapping.
int Delete(MacOsSecItemQuery query)
Deletes the generic-password record identified by query
.
query
The raw OSStatus, which the v2 store maps through its local-secret status mapping.
Stores AppSurface LocalSecrets values for one machine and user context.
Implementations should use display-safe diagnostics for expected platform failures. Raw secret values may be returned only through Get(AppSurfaceLocalSecretIdentity)
when the status is LocalSecretResultStatus.Found
.
AppSurfaceLocalSecretResult Get(AppSurfaceLocalSecretIdentity identity)
Reads a local secret.
identity
The store result.
AppSurfaceLocalSecretResult Set(AppSurfaceLocalSecretIdentity identity, string value)
Writes a local secret.
identity
value
The store result. Successful writes return LocalSecretResultStatus.Found
with no value.
AppSurfaceLocalSecretResult Delete(AppSurfaceLocalSecretIdentity identity)
Deletes a local secret.
identity
The store result. Platform-indexed stores may return LocalSecretResultStatus.Found
when the value was already missing but a stale indexed name was removed; keys that were never stored still return LocalSecretResultStatus.Missing
when the store can confirm no stale index entry remains. If the platform index cannot be read, platform-indexed stores fail closed instead of assuming the key was never indexed.
AppSurfaceLocalSecretListResult List(string applicationName, string environment, string? keyPrefix)
Lists currently retrievable local secret config keys for an application/environment namespace.
applicationName
environment
keyPrefix
The list result. Platform-indexed stores validate indexed names against live stored values and may prune missing entries after a successful validation pass. Corrupt indexes and terminal platform failures return display-safe diagnostics instead of hiding unverified names.
AppSurfaceLocalSecretResult Doctor(string applicationName, string environment, string? keyPrefix)
Diagnoses whether the store is usable for the supplied namespace.
applicationName
environment
keyPrefix
A display-safe store diagnostic result.
string Name { get; }
Source
Gets the display-safe store name.
Describes a display-safe local secret diagnostic.
Diagnostics are safe to render in command output, audit reports, and exception messages. They must never carry raw secret values. Use ToTerminalDiagnostic
when the diagnostic should stop lower-priority configuration provider resolution.
ConfigProviderTerminalDiagnostic ToTerminalDiagnostic()
Converts this local secret diagnostic into a Config terminal diagnostic.
A terminal diagnostic safe for runtime configuration resolution errors.
string ToDisplayString()
Formats this diagnostic for display without exposing secret values.
A multiline display-safe diagnostic string.
string Code { get; }
Source
Gets the stable machine-readable diagnostic code.
string Problem { get; }
Source
Gets the display-safe problem summary.
string Cause { get; }
Source
Gets the display-safe cause summary.
string Fix { get; }
Source
Gets the suggested recovery action.
string? Docs { get; }
Source
Gets an optional documentation hint or URL.
bool Retryable { get; }
Source
Gets a value indicating whether retrying later may resolve the condition.
Provides service collection helpers for AppSurface LocalSecrets.
IServiceCollection ConfigureAppSurfaceLocalSecrets(this IServiceCollection services, Action<AppSurfaceLocalSecretsOptions> configure)
Configures LocalSecrets options.
services
configure
The original service collection.
IServiceCollection UseAppSurfaceLocalSecretStore<TStore>(this IServiceCollection services)
Replaces the local secret store implementation.
TStore
services
The original service collection.
IServiceCollection UseAppSurfaceLocalSecretStore(this IServiceCollection services, IAppSurfaceLocalSecretStore store)
Replaces the local secret store with a specific instance.
services
store
The original service collection.
Describes local secret identity normalization.
Identity
Diagnostic
AppSurfaceLocalSecretIdentityResult Valid(AppSurfaceLocalSecretIdentity identity)
Creates a successful identity result.
identity
A successful result.
AppSurfaceLocalSecretIdentityResult Invalid(AppSurfaceLocalSecretDiagnostic diagnostic)
Creates a failed identity result.
diagnostic
A failed result.
bool Succeeded { get; }
Source
Gets a value indicating whether normalization succeeded.
AppSurface configuration provider that resolves values from the local secret store.
The provider sits above file configuration and below environment variables. Only true missing secrets fall through; store, posture, identity, and conversion failures are terminal when fail-closed behavior is enabled.
AppSurfaceLocalSecretResolution<T> ResolveValue<T>(string environment, string key)
Resolves a local secret and returns the structured LocalSecrets status before config-provider adaptation.
T
environment
key
The typed LocalSecrets resolution.
In-memory LocalSecrets store intended for tests and controlled local examples.
This store is not durable and is not a production or development secret store. It exists as a package-local test seam so apps can verify LocalSecrets provider behavior without touching the platform credential store.
Normalizes LocalSecrets app, environment, prefix, and key values into a stable storage identity.
The normalizer is the boundary between logical AppSurface config keys and platform-specific local secret names. Application, environment, and prefix segments are trimmed, capped at 128 characters, and limited to ASCII letters, digits, dash, underscore, and dot where documented. Whitespace in segments becomes -
. Config keys are trimmed, capped at 256 characters, reject nulls and line breaks, normalize __
to :
, and normalize \
to /
. When the application name is omitted, the normalizer infers one from the entry assembly, then the current directory, then AppSurfaceApp
; pin AppSurfaceLocalSecretsOptions.ApplicationName
for published apps so deployment shape or working-directory changes do not move the local secret namespace.
AppSurfaceLocalSecretIdentityResult Normalize(string? applicationName, string environment, string? keyPrefix, string key)
Normalizes a local secret identity.
applicationName
environment
keyPrefix
key
A normalized identity result.
A successful result contains normalized display segments and a storage name in the form appsurface:{application}:{environment}:{key}
, or appsurface:{application}:{environment}:{prefix}:{key}
when a prefix is configured. Invalid input returns a display-safe diagnostic rather than throwing so command and provider paths can render paste-safe guidance.
File-backed LocalSecrets store for deterministic local workflows and tests.
This store is useful when OS credential tooling is unavailable in CI or examples. It is not the default platform store and should not be used as a production vault. The file contains secret values and must stay outside source control.
string GetDefaultPath()
Gets the default per-user AppSurface local secret file path.
A path under the user's local application data directory.
Provides filesystem operations for the explicit file-backed LocalSecrets store.
The seam keeps posture checks ordered around raw secret IO: read inspection must finish before file contents are opened, write preparation may create only missing directories, and doctor may repair only the fallback file itself.
bool FileExists(string path)
Returns whether the configured fallback file exists.
path
true
when the fallback file exists.
string ReadAllText(string path)
Reads the fallback JSON file after posture inspection has already succeeded.
path
The raw JSON contents.
Stream OpenRead(string path)
Opens the fallback JSON file for metadata-only streaming scans after posture inspection has already succeeded.
path
A readable stream for the raw JSON contents.
FileSecretPostureResult InspectReadPath(string path)
Inspects only the path shape needed before read attempts that do not need file mode posture.
path
The path-shape posture result.
FileSecretPostureResult InspectExistingFilePosture(string path)
Inspects the existing fallback file and immediate containing directory before returning or reading secret values.
path
The existing-file posture result.
FileSecretPostureResult PrepareWrite(string path)
Prepares the fallback path for a write without reading or mutating existing parent directory permissions.
path
The write-preparation posture result.
FileSecretPostureResult WriteAllTextWithPosture(string path, string contents)
Atomically writes the fallback JSON file and repairs the final file mode when the platform supports it.
path
contents
The write posture result.
FileSecretPostureResult Doctor(string path)
Opens or creates the fallback file and reports ready, repaired, degraded, or unsupported posture.
path
The doctor posture result.
Default filesystem adapter for the explicit file-backed LocalSecrets store.
The adapter validates path shape, Unix mode posture, and write ordering without broad filesystem mutation. Missing fallback directories may be created, but existing loose directories are reported for the caller to fix deliberately.
DefaultFileAppSurfaceLocalSecretStoreFileSystem Instance { get; }
Source
Gets the singleton production adapter.
Carries a posture outcome and the value-safe diagnostic text shown by LocalSecrets commands.
Kind
Code
Problem
Cause
Fix
Retryable
FileSecretPostureResult Ready()
FileSecretPostureResult Repaired()
Creates a repaired posture result for fallback files tightened by write or doctor.
A repaired posture result.
FileSecretPostureResult Degraded()
Creates a degraded posture result for platforms where owner-only posture cannot be proven in v1.
A degraded posture result.
FileSecretPostureResult Unsupported(string code, string problem, string cause, string fix)
Creates an unsupported posture result for unsafe path shapes or permanent posture violations.
code
problem
cause
fix
An unsupported posture result.
AppSurfaceLocalSecretDiagnostic ToDiagnostic()
Converts the posture result to a LocalSecrets diagnostic.
The value-safe LocalSecrets diagnostic.
Probes LocalSecrets metadata without returning raw secret values.
Transfer workflows use this seam for dry-run planning and overwrite checks so they can answer whether a local identity is known without calling IAppSurfaceLocalSecretStore.Get(AppSurfaceLocalSecretIdentity)
. Implementations must return display-safe diagnostics and must not put secret payloads in successful probe results. Platform stores may use their LocalSecrets index as metadata; stale indexed entries are verified later when an apply operation performs the value read that is required for transfer.
AppSurfaceLocalSecretResult Probe(AppSurfaceLocalSecretIdentity identity)
Probes whether a local secret identity is present in store metadata.
identity
A display-safe result. LocalSecretResultStatus.Found
means the identity is present in metadata; LocalSecretResultStatus.Missing
means the store can confirm no metadata entry exists.
Represents platform selections used by deterministic platform-store tests.
Describes the file-system state of a candidate Linux secret-tool
path.
The states deliberately separate existence from executability so diagnostics can distinguish missing binaries, directory mistakes, and files that exist but cannot be launched.
Identifies whether a platform secret command result came from an exited process or a runner-level synthetic failure.
Defines where LocalSecrets is allowed to participate in configuration resolution.
Numeric values are part of the public AppSurface LocalSecrets contract and must remain stable. The zero value is DevelopmentOnly
so CLR default enum initialization matches the documented provider default.
Identifies the action taken for one LocalSecrets migration row.
Use AppSurfaceLocalSecretMigrationActionExtensions.ToDisplayString(AppSurfaceLocalSecretMigrationAction)
when rendering an action for an operator. The text remains stable so command output is compatible with the initial macOS v2 migration workflow.
Identifies the outcome of a local secret lookup or mutation.
Only Missing
represents true absence and may fall through to lower-priority configuration providers. All other non-found states are terminal for a LocalSecrets-claimed key. Numeric values are part of the public AppSurface LocalSecrets contract and must remain stable because status values may appear in diagnostics, tests, serialized examples, or package-consumer switch expressions.
Describes the posture outcome for the explicit file fallback.