feat: 1Password Connect secret sources for SSH credentials (#1341)

* feat: 1Password Connect secret sources for SSH credentials

Hosts and credentials can hold op://vault/item/field references instead
of secrets; they are resolved at connect time from the user's secret
source (1Password Connect) at the single point where every subsystem
receives plaintext credentials, so terminal, SFTP, Docker, metrics and
tunnels all work without per-subsystem changes. Sources are per user,
optionally shared, with the access token encrypted under the owner's
data key; resolved values are cached briefly in memory.

* style: format secret source changes
This commit is contained in:
ZacharyZcR
2026-08-25 03:06:37 +08:00
committed by GitHub
parent 32d77fc6d0
commit 5f55289e00
34 changed files with 28148 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
import { authApi, handleApiError } from "@/main-axios";
export interface SecretSource {
id: string;
userId: string;
name: string;
kind: "onepassword-connect";
baseUrl: string;
shared: boolean;
hasToken: boolean;
owned: boolean;
createdAt: string;
updatedAt: string;
}
export interface SecretSourcePayload {
name: string;
kind?: "onepassword-connect";
baseUrl: string;
token?: string;
shared?: boolean;
}
export async function listSecretSources(): Promise<SecretSource[]> {
try {
return (await authApi.get("/secret-sources")).data.sources;
} catch (error) {
throw handleApiError(error, "list secret sources");
}
}
export async function createSecretSource(
payload: SecretSourcePayload,
): Promise<SecretSource> {
try {
return (await authApi.post("/secret-sources", payload)).data.source;
} catch (error) {
throw handleApiError(error, "create secret source");
}
}
export async function updateSecretSource(
id: string,
payload: Partial<SecretSourcePayload>,
): Promise<void> {
try {
await authApi.put(`/secret-sources/${id}`, payload);
} catch (error) {
throw handleApiError(error, "update secret source");
}
}
export async function deleteSecretSource(id: string): Promise<void> {
try {
await authApi.delete(`/secret-sources/${id}`);
} catch (error) {
throw handleApiError(error, "delete secret source");
}
}
export async function testSecretSource(
id: string,
): Promise<{ ok: boolean; vaults?: number; error?: string }> {
try {
return (await authApi.post(`/secret-sources/${id}/test`)).data;
} catch (error) {
throw handleApiError(error, "test secret source");
}
}