feat(prd-0048): implement SSH deploy-key provisioning with contrib/gitea
- manifest_git.py: add ProvisionedKeyConfig dataclass; extend GitEntry with ProvisionedKey field (optional); make IdentityFile default to "" so provisioned_key entries can be constructed without a static path; add _parse_provisioned_key_config; update from_repos_entry to accept provisioned_key as an alternative to identity (mutually exclusive, parser rejects both-or-neither) - deploy_key_provisioner.py (new): DeployKeyProvisioner ABC with create() and delete() abstract methods; get_provisioner() factory with lazy contrib import for gitea - contrib/gitea/deploy_key_provisioner.py (new): GiteaDeployKeyProvisioner generating ed25519 keypairs via ssh-keygen and managing them through the Gitea deploy-key API (POST/DELETE); 404 on delete is success; all other errors raise RuntimeError - git_gate.py: add _provision_dynamic_key() called in GitGate.prepare() for entries with ProvisionedKey — generates key, writes private key and key ID files to stage_dir, patches GitGateUpstream.identity_file; add revoke_git_gate_provisioned_keys() for teardown — raises on failure - docker/launch.py: call revoke_git_gate_provisioned_keys() in teardown() after stack.close() so revocation runs after containers stop and failures propagate (not suppressed) - smolmachines/launch.py: extract _teardown_smolmachines() helper that catches stack.close() errors (warn + re-raise) then calls revocation; same fatal-on-failure contract as docker backend - test_manifest_git.py: 9 new cases for provisioned_key parsing - test_deploy_key_provisioner.py (new): factory smoke tests - test_contrib_gitea_deploy_key.py (new): create/delete/error/split tests Closes #169
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
"""Unit: deploy_key_provisioner factory (PRD 0048)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from bot_bottle.deploy_key_provisioner import DeployKeyProvisioner, get_provisioner
|
||||
from bot_bottle.manifest import ManifestError
|
||||
|
||||
|
||||
class TestGetProvisioner(unittest.TestCase):
|
||||
def test_gitea_returns_gitea_provisioner(self):
|
||||
from bot_bottle.contrib.gitea.deploy_key_provisioner import (
|
||||
GiteaDeployKeyProvisioner,
|
||||
)
|
||||
p = get_provisioner("gitea", token="tok", api_url="https://gitea.example.com")
|
||||
self.assertIsInstance(p, GiteaDeployKeyProvisioner)
|
||||
self.assertIsInstance(p, DeployKeyProvisioner)
|
||||
|
||||
def test_unknown_provider_raises_manifest_error(self):
|
||||
with self.assertRaises(ManifestError) as ctx:
|
||||
get_provisioner("github", token="tok", api_url="https://github.com")
|
||||
self.assertIn("github", str(ctx.exception))
|
||||
self.assertIn("provisioned_key provider", str(ctx.exception))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user