mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-08-15 07:17:30 +00:00
Private keys have lived as plaintext-on-disk files guarded only by a passphrase. This puts them in the same end-to-end-encrypted vaults as .env secrets, and adds an agent path so a machine can use a key without ever writing one to its disk. - `ssh` provider: ~/.ssh as a value bag. Files are picked by sniffing contents (PRIVATE KEY blocks, ssh-*/ecdsa-*/sk-* public keys) plus config, config.d/* and allowed_signers. known_hosts and authorized_keys are host-specific and access-granting, so they need an explicit --include. - Each file is one secret carrying a JSON envelope of path, mode and body. The engine only hands write() the secrets that CHANGED, so a separate manifest secret would be absent whenever a key's contents change but the file list doesn't — self-describing values keep every restore total. - `logicsrc secrets ssh push|pull|list|agent`, addressed by PERSON not project: the vault is ssh--<username>, which teams vaults reads as project ssh, env <username>. One teammate's keys never land in another's restore; sharing stays a deliberate teams grant. - Both directions hold back anything that would overwrite a file that already differs, and say what they skipped. --force opts in. A restore onto a machine with its own keys is otherwise a way to lose them. - Restores chmod each file back to its recorded mode; writeFileSync's mode applies only on create, so an existing world-readable key would otherwise stay world-readable. The adapter declares delete:false. - push warns about passphrase-less private keys before they go up. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
123 lines
3.6 KiB
TypeScript
123 lines
3.6 KiB
TypeScript
import type { PluginDefinition } from "@logicsrc/plugin-core";
|
|
import { credentialSharingManifest } from "./manifest.js";
|
|
import { CredentialEngine, type CredentialEngineOptions } from "./engine.js";
|
|
import { listCredentialProviderManifests } from "./providers/index.js";
|
|
|
|
export const credentialSharingPlugin: PluginDefinition = {
|
|
manifest: credentialSharingManifest,
|
|
configDefaults: {
|
|
enabled: true,
|
|
default_policy: "approval_required_for_destructive",
|
|
credential_home: "${LOGICSRC_CREDENTIAL_HOME}"
|
|
},
|
|
routes: [
|
|
{ method: "GET", path: "/api/credentials/providers", capability: "credentials.providers.list" },
|
|
{ method: "GET", path: "/api/credentials/inspect", capability: "credentials.inspect" },
|
|
{ method: "POST", path: "/api/credentials/diff", capability: "credentials.diff" },
|
|
{ method: "POST", path: "/api/credentials/plans", capability: "credentials.plan" },
|
|
{ method: "POST", path: "/api/credentials/plans/:id/approve", capability: "credentials.approve" },
|
|
{ method: "POST", path: "/api/credentials/plans/:id/sync", capability: "credentials.sync" },
|
|
{ method: "POST", path: "/api/credentials/runs/:id/rollback", capability: "credentials.rollback" },
|
|
{ method: "GET", path: "/api/credentials/runs/:id/audit", capability: "credentials.audit.read" }
|
|
],
|
|
permissions: [
|
|
"credentials:inspect",
|
|
"credentials:diff",
|
|
"credentials:plan",
|
|
"credentials:approve",
|
|
"credentials:sync",
|
|
"credentials:rollback",
|
|
"credentials:audit:read"
|
|
],
|
|
tuiPanels: [{ id: "credential-sharing", title: "Credential Sharing" }]
|
|
};
|
|
|
|
/** Factory mirroring the LogicSRC Credential Sharing SDK spec. */
|
|
export function createCredentialEngine(options: CredentialEngineOptions = {}): CredentialEngine {
|
|
return new CredentialEngine(options);
|
|
}
|
|
|
|
/** Provider listing without constructing an engine (used by the CLI `providers` command). */
|
|
export function listCredentialProviders() {
|
|
return listCredentialProviderManifests();
|
|
}
|
|
|
|
export { credentialSharingManifest };
|
|
export { CredentialEngine, DEFAULT_CREDENTIAL_POLICY, endpointLabel } from "./engine.js";
|
|
export type { CredentialEngineOptions } from "./engine.js";
|
|
export {
|
|
credentialProviders,
|
|
credentialProviderRegistry,
|
|
listCredentialProviderManifests,
|
|
envProvider,
|
|
dopplerProvider,
|
|
railwayProvider,
|
|
githubSecretsProvider,
|
|
sshProvider,
|
|
teamProvider,
|
|
parseEnv,
|
|
applyEnv,
|
|
classifySshFile,
|
|
decodeSshFile,
|
|
defaultSshDirectory,
|
|
encodeSshFile,
|
|
isPassphraseless,
|
|
readSshDirectory,
|
|
secretNameForPath,
|
|
sshDirectory,
|
|
SSH_ENVELOPE_VERSION,
|
|
type SshFile,
|
|
type SshFileKind
|
|
} from "./providers/index.js";
|
|
export {
|
|
TeamClient,
|
|
TeamApiError,
|
|
type TeamClientOptions,
|
|
type RemoteUser,
|
|
type RemoteTeam,
|
|
type RemoteMember,
|
|
type RemoteVault,
|
|
type RemoteSecret,
|
|
type RemoteGrantRow
|
|
} from "./client.js";
|
|
export {
|
|
generateIdentityKeyPair,
|
|
generateVaultKey,
|
|
wrapVaultKey,
|
|
unwrapVaultKey,
|
|
encryptValue,
|
|
decryptValue,
|
|
publicKeyForSecret,
|
|
type IdentityKeyPair,
|
|
type SealedValue
|
|
} from "./crypto.js";
|
|
export {
|
|
loadOrCreateIdentity,
|
|
readIdentity,
|
|
saveIdentity,
|
|
updateIdentity,
|
|
requireAuth,
|
|
verifyIdentityIntegrity,
|
|
identityPath,
|
|
logicsrcHome,
|
|
defaultApiUrl,
|
|
envApiUrl,
|
|
resolveApiUrl,
|
|
DEFAULT_API_URL,
|
|
type LocalIdentity
|
|
} from "./identity.js";
|
|
export {
|
|
createFileCredentialStore,
|
|
createMemoryCredentialStore,
|
|
defaultCredentialHome,
|
|
type CredentialStore
|
|
} from "./store.js";
|
|
export { fingerprintValue, fingerprintsEqual } from "./fingerprint.js";
|
|
export {
|
|
planVaultRekey,
|
|
type RekeyPlan,
|
|
type RekeyPlanInput,
|
|
type RekeyMember,
|
|
type SealedSecret
|
|
} from "./rekey.js";
|
|
export * from "./types.js";
|