diff options
| author | Christian Cleberg <[email protected]> | 2026-08-07 16:29:04 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-08-07 16:29:04 -0500 |
| commit | 07156180789b02d4f22a87f22a37c912e7543190 (patch) | |
| tree | 6d943fc410b37d3dc7dfec72406688dbd97ac724 /Hutch/Networking/RepositoryDeployKeyService.swift | |
| parent | 18b1c475983ae9e6a52fcedb2e2992193130035c (diff) | |
| download | hutch-07156180789b02d4f22a87f22a37c912e7543190.tar.gz hutch-07156180789b02d4f22a87f22a37c912e7543190.tar.bz2 hutch-07156180789b02d4f22a87f22a37c912e7543190.zip | |
Deploy keys: manage git.sr.ht repository deploy keys (v3.10.0)
Wire git.sr.ht createDeployKey / deleteDeployKey and Repository.deployKeys
into an owner-only Deploy Keys sheet in the repository actions menu, next to
ACLs: list keys (fingerprint, comment, access), add an SSH public key with
RO/RW access, and delete behind a confirmation.
Verified live against the ~hutch account. The createDeployKey response
returns an empty access value, so create selects only rid and the list is
reloaded rather than decoding the partial key.
Bumps to 3.10.0 (build 95); roadmap marks deploy keys shipped.
Diffstat (limited to 'Hutch/Networking/RepositoryDeployKeyService.swift')
| -rw-r--r-- | Hutch/Networking/RepositoryDeployKeyService.swift | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/Hutch/Networking/RepositoryDeployKeyService.swift b/Hutch/Networking/RepositoryDeployKeyService.swift new file mode 100644 index 0000000..39e2da1 --- /dev/null +++ b/Hutch/Networking/RepositoryDeployKeyService.swift @@ -0,0 +1,100 @@ +import Foundation + +/// A per-repository deploy key (git.sr.ht `SSHKey` under `Repository.deployKeys`). +struct RepositoryDeployKey: Decodable, Sendable, Identifiable, Hashable { + let rid: String + let keyType: String + let fingerprintSHA256: String + let comment: String? + let access: AccessMode + + var id: String { rid } +} + +private struct DeployKeysQueryResponse: Decodable, Sendable { + let repository: DeployKeysRepository? +} + +private struct DeployKeysRepository: Decodable, Sendable { + let deployKeys: DeployKeysPage +} + +private struct DeployKeysPage: Decodable, Sendable { + let results: [RepositoryDeployKey] +} + +/// `createDeployKey`'s response returns an empty `access` (the stored value is +/// correct — the list query reports it), so we select only `rid` here and let +/// callers reload rather than decode the partial key. +private struct CreateDeployKeyResponse: Decodable, Sendable {} + +/// Delete returns the removed key; only success matters here. +private struct DeleteDeployKeyResponse: Decodable, Sendable {} + +/// Deploy keys are a git.sr.ht capability (`createDeployKey` / `deleteDeployKey`), +/// owner-only, alongside repository ACLs. +struct RepositoryDeployKeyService: Sendable { + private let client: SRHTClient + + init(client: SRHTClient) { + self.client = client + } + + func fetchDeployKeys(repositoryRid: String) async throws -> [RepositoryDeployKey] { + let response = try await client.execute( + service: .git, + query: Self.deployKeysQuery, + variables: ["rid": repositoryRid], + responseType: DeployKeysQueryResponse.self + ) + return response.repository?.deployKeys.results ?? [] + } + + func createDeployKey(repositoryRid: String, mode: AccessMode, key: String) async throws { + _ = try await client.execute( + service: .git, + query: Self.createDeployKeyMutation, + variables: ["repo": repositoryRid, "mode": mode.rawValue, "key": key], + responseType: CreateDeployKeyResponse.self + ) + } + + func deleteDeployKey(rid: String) async throws { + _ = try await client.execute( + service: .git, + query: Self.deleteDeployKeyMutation, + variables: ["rid": rid], + responseType: DeleteDeployKeyResponse.self + ) + } +} + +private extension RepositoryDeployKeyService { + static let deployKeysQuery = """ + query repositoryDeployKeys($rid: ID!) { + repository(rid: $rid) { + deployKeys { + results { + rid + keyType + fingerprintSHA256 + comment + access + } + } + } + } + """ + + static let createDeployKeyMutation = """ + mutation createDeployKey($repo: ID!, $mode: AccessMode!, $key: String!) { + createDeployKey(repo: $repo, mode: $mode, key: $key) { rid } + } + """ + + static let deleteDeployKeyMutation = """ + mutation deleteDeployKey($rid: ID!) { + deleteDeployKey(rid: $rid) { rid } + } + """ +} |
