feat(app): Secrets management page + backend-aware API
- new Secrets page (/secrets, nav entry): lists vault secrets, reveal/copy, add/edit/delete, shows active backend + addr + role; read-only on followers - GET /secrets/info (backend/addr/role/writable); fix /secrets CRUD to use the castle.yaml-selected backend (was defaulting to the now-empty file backend) - OpenBaoBackend.list_names drops folder entries (node-prefix groups) - tests: conftest forces file backend so host castle.yaml can't leak into tests app builds clean (tsc 0); endpoints verified live against the vault.
This commit is contained in:
@@ -543,3 +543,43 @@ export function useEventStream() {
|
||||
return () => es.close()
|
||||
}, [qc])
|
||||
}
|
||||
|
||||
// --- Secrets ---
|
||||
|
||||
export interface SecretsInfo {
|
||||
backend: string
|
||||
addr: string | null
|
||||
role: string
|
||||
writable: boolean
|
||||
}
|
||||
|
||||
export function useSecretsInfo() {
|
||||
return useQuery({
|
||||
queryKey: ["secrets-info"],
|
||||
queryFn: () => apiClient.get<SecretsInfo>("/secrets/info"),
|
||||
})
|
||||
}
|
||||
|
||||
export function useSecrets() {
|
||||
return useQuery({
|
||||
queryKey: ["secrets"],
|
||||
queryFn: () => apiClient.get<string[]>("/secrets"),
|
||||
})
|
||||
}
|
||||
|
||||
export function useSetSecret() {
|
||||
const qc = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: ({ name, value }: { name: string; value: string }) =>
|
||||
apiClient.put(`/secrets/${name}`, { value }),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ["secrets"] }),
|
||||
})
|
||||
}
|
||||
|
||||
export function useDeleteSecret() {
|
||||
const qc = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: (name: string) => apiClient.delete(`/secrets/${name}`),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ["secrets"] }),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user