You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracking parent: No production commit lands directly against this issue. Implementation is complete only through the structurally attached one-commit detail issues below.
Implement stored-secret, environment, and GitHub CLI executors behind IAccessBroker, preserve fail-closed opaque manifest handles, and remove the parallel ISecretProvider, modal consent, static GitHub resolver, IApiKeyResolver, and direct token delegate paths. This is a direct final cutover with no adapters or grant migration.
Current Limitation / Root Cause
Services/Secrets/SecretProvider.cs batches unresolved uses, persists old scope/source records, and only then resolves values. GitHubAuthTokenResolver reads GITHUB_TOKEN or invokes gh auth token outside common policy. AgentFactory, CopilotSdkChatClient, repository/persistence factories, and usage providers retain direct environment/API-key/GitHub paths. SecretRetriever can return the same SecureString across uses. These paths cannot enforce authorization-before-read, exact source/generation, independent lease ownership, or broker-wide shutdown.
StoredSecretAccessExecutor.InspectAsync may enumerate safe store names/existence and environment source availability; it cannot call ReadAsync or read an environment value. GitHubCredentialAccessExecutor.InspectAsync identifies configured environment/CLI/cache source metadata but cannot read GITHUB_TOKEN or invoke gh.
After broker approval, ExecuteAsync reads exactly the selected source and validates its identity. Allow is valid only for an inspection marked usable; if the entry disappears, return renewal-needed and update the same row. Never switch source silently. gh auth token output is reduced directly into an independently owned lease and never logged. If an interactive GitHub executor is absent, missing credentials return sanitized failure rather than a false Perform row.
Manifest scanning retains ${SECRET:<opaque-use-handle>} and fail-closed materialization, but every occurrence submits its own named-initializer StoredSecretAccessRequest. The handle points to an independently owned lease, not a shared retriever. UseAsync is invoked only at the final SDK/HTTP constructor boundary.
Replace old grants with IReleaseAuthorizationPolicy; do not read, transform, or migrate old records. Remove OAuthSecretSource: OAuth is a provider route. Directly remove ISecretProvider, SecretUseDialog, static resolver/API-key abstractions, and production delegates after their call sites move in this issue.
Part of #1505
Parent
[access-broker] - Unify credential-use authorization, acquisition, renewal, and presentationDependencies
Summary
Tracking parent: No production commit lands directly against this issue. Implementation is complete only through the structurally attached one-commit detail issues below.
Implement stored-secret, environment, and GitHub CLI executors behind
IAccessBroker, preserve fail-closed opaque manifest handles, and remove the parallelISecretProvider, modal consent, static GitHub resolver,IApiKeyResolver, and direct token delegate paths. This is a direct final cutover with no adapters or grant migration.Current Limitation / Root Cause
Services/Secrets/SecretProvider.csbatches unresolved uses, persists old scope/source records, and only then resolves values.GitHubAuthTokenResolverreadsGITHUB_TOKENor invokesgh auth tokenoutside common policy.AgentFactory,CopilotSdkChatClient, repository/persistence factories, and usage providers retain direct environment/API-key/GitHub paths.SecretRetrievercan return the sameSecureStringacross uses. These paths cannot enforce authorization-before-read, exact source/generation, independent lease ownership, or broker-wide shutdown.Affected Files
Llm.Interfaces/Access/StoredSecretAccessContracts.csLlm.Interfaces/Access/GitHubCredentialAccessContracts.csServices/Access/StoredSecretAccessExecutor.cs(new)Services/Access/GitHubCredentialAccessExecutor.cs(new)Llm.Core/Secrets/AgentDefinitionSecretMaterializer.csLlm.Core/Secrets/*,Services/Secrets/*GitHubAuthTokenResolver.cs,IApiKeyResolver.cs,EnvironmentApiKeyResolver.csAgentFactory.cs,CopilotSdkChatClient.cs, repository/persistence/usage consumersDesign / Fix
StoredSecretAccessExecutor.InspectAsyncmay enumerate safe store names/existence and environment source availability; it cannot callReadAsyncor read an environment value.GitHubCredentialAccessExecutor.InspectAsyncidentifies configured environment/CLI/cache source metadata but cannot readGITHUB_TOKENor invokegh.After broker approval,
ExecuteAsyncreads exactly the selected source and validates its identity.Allowis valid only for an inspection marked usable; if the entry disappears, return renewal-needed and update the same row. Never switch source silently.gh auth tokenoutput is reduced directly into an independently owned lease and never logged. If an interactive GitHub executor is absent, missing credentials return sanitized failure rather than a false Perform row.Manifest scanning retains
${SECRET:<opaque-use-handle>}and fail-closed materialization, but every occurrence submits its own named-initializerStoredSecretAccessRequest. The handle points to an independently owned lease, not a shared retriever.UseAsyncis invoked only at the final SDK/HTTP constructor boundary.Replace old grants with
IReleaseAuthorizationPolicy; do not read, transform, or migrate old records. RemoveOAuthSecretSource: OAuth is a provider route. Directly removeISecretProvider,SecretUseDialog, static resolver/API-key abstractions, and production delegates after their call sites move in this issue.Implementation Detail Issues
Commit Plan
StoredSecretAccessExecutorAgentDefinitionSecretMaterializer,SecretPlaceholderResolverGitHubCredentialAccessExecutorAgentFactory,CopilotSdkChatClient, typedAgentServicesslotEntityRepository,AgentPersistenceStoreSourceFactoryGitHubCredentialUsageAdapterISecretProvider,SecretProvider,GitHubAuthTokenResolverIApiKeyResolver,EnvironmentApiKeyResolver,OAuthSecretSourceSecurity and Privacy Invariants
SecureString.Tracking-parent acceptance
Exclusions
Expected Tests
InspectAsync_PlatformStore_DoesNotReadSecretValueStoredSecretAccessExecutorTestsExecuteAsync_PlatformStore_ReadsOnlyAfterReleaseCommitStoredSecretAccessExecutorTestsExecuteAsync_SelectedSourceMissing_ReturnsRenewalNeededWithoutSwitchingSourceStoredSecretAccessExecutorTestsAgentDefinitionSecretMaterializer_MultipleUses_SubmitsIndependentBrokerRequestsAgentDefinitionSecretMaterializerTestsAgentDefinitionSecretMaterializer_AccessFailure_FailsClosedWithoutPlaintextPlaceholderAgentDefinitionSecretMaterializerTestsGitHubExecutor_InspectAsync_DoesNotReadEnvironmentOrInvokeCliGitHubCredentialAccessExecutorTestsGitHubExecutor_ExecuteAsync_CliSource_InvokesAfterApprovalAndDoesNotLogStdoutGitHubCredentialAccessExecutorTestsGitHubExecutor_CompatibleCallers_ReturnIndependentLeasesGitHubCredentialAccessExecutorTestsGitHubExecutor_ResolvedAccountMismatch_FailsClosedGitHubCredentialAccessExecutorTestsAccessMigration_SecretGitHubAndApiKeyCallers_UseAccessBrokerOnlyAccessMigrationTestsAccessMigration_OldSecretProviderAndOAuthSecretSource_HaveNoProductionReferencesAccessMigrationTests