docs(FN-011): complete Step 8 — update architecture and development docs
Fusion-Task-Id: FN-011 Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
This commit is contained in:
+26
-3
@@ -30,17 +30,40 @@ The backend must define provider contracts before implementing any concrete adap
|
|||||||
|
|
||||||
### 3.1 GitProvider
|
### 3.1 GitProvider
|
||||||
|
|
||||||
|
> **Architecture divergence note (FN-011):** The original spec defined a single
|
||||||
|
> `GitProvider(Protocol)` with `clone/fetch/push` methods. The implementation
|
||||||
|
> intentionally splits this responsibility into two abstractions:
|
||||||
|
>
|
||||||
|
> - `GitProvider` (`app/git/provider.py`) — provider API adapter for remote
|
||||||
|
> operations (`validate_connection`, `list_repositories`, `create_deploy_key`,
|
||||||
|
> etc.).
|
||||||
|
> - `GitOperations` (`app/git/operations.py`) — local Git subprocess interface
|
||||||
|
> (`clone`, `fetch`, `push`, `get_status`).
|
||||||
|
>
|
||||||
|
> This separation keeps provider-specific API logic distinct from local Git CLI
|
||||||
|
> orchestration.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class GitProvider(Protocol):
|
class GitProvider(Protocol):
|
||||||
def clone(self, repo_url: str, dest: Path, credentials: GitCredentials) -> None: ...
|
def validate_connection(self, repo_url: str, credential_id: str) -> ConnectionStatus: ...
|
||||||
def fetch(self, repo_path: Path, credentials: GitCredentials) -> None: ...
|
def list_repositories(self, credential_id: str) -> list[dict[str, Any]]: ...
|
||||||
def push(self, repo_path: Path, credentials: GitCredentials) -> None: ...
|
def create_deploy_key(self, repo_url: str, public_key: str) -> str: ...
|
||||||
|
def delete_deploy_key(self, repo_url: str, deploy_key_id: str) -> None: ...
|
||||||
|
def get_default_branch(self, repo_url: str, credential_id: str) -> str: ...
|
||||||
```
|
```
|
||||||
|
|
||||||
- Adapters: GitHub, GitLab, Gitea, Forgejo, etc.
|
- Adapters: GitHub, GitLab, Gitea, Forgejo, etc.
|
||||||
- Credentials: generated SSH keys (per-repository) or access tokens.
|
- Credentials: generated SSH keys (per-repository) or access tokens.
|
||||||
- SSH keys must be scoped per repository connection for clean revocation.
|
- SSH keys must be scoped per repository connection for clean revocation.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class GitOperations(Protocol):
|
||||||
|
def clone(self, repo_url: str, dest: Path, credential_id: str) -> None: ...
|
||||||
|
def fetch(self, repo_path: Path, credential_id: str) -> None: ...
|
||||||
|
def push(self, repo_path: Path, credential_id: str) -> None: ...
|
||||||
|
def get_status(self, repo_path: Path) -> dict[str, Any]: ...
|
||||||
|
```
|
||||||
|
|
||||||
### 3.2 RuntimeProvider
|
### 3.2 RuntimeProvider
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|||||||
@@ -175,3 +175,23 @@ pnpm build
|
|||||||
- **Frontend**: React functional components, TypeScript strict mode, ESLint + Ruff-like rules.
|
- **Frontend**: React functional components, TypeScript strict mode, ESLint + Ruff-like rules.
|
||||||
- **Backend**: FastAPI, Pydantic settings, pytest, ruff, mypy.
|
- **Backend**: FastAPI, Pydantic settings, pytest, ruff, mypy.
|
||||||
- **Commits**: Conventional commits with task ID prefix, e.g. `feat(FN-002): description`.
|
- **Commits**: Conventional commits with task ID prefix, e.g. `feat(FN-002): description`.
|
||||||
|
|
||||||
|
## Git Abstraction
|
||||||
|
|
||||||
|
The `app/git/` package in the backend provides provider-independent Git
|
||||||
|
orchestration. It is split into two layers so that remote provider API logic
|
||||||
|
and local CLI operations evolve independently:
|
||||||
|
|
||||||
|
| Module | Responsibility |
|
||||||
|
|--------|--------------|
|
||||||
|
| `types` | Enumerations (`ProviderKind`, `CredentialKind`, `ConnectionStatus`, `SshKeyStatus`) |
|
||||||
|
| `provider` | Abstract `GitProvider` — remote operations (`validate_connection`, `list_repositories`, `create_deploy_key`, …) |
|
||||||
|
| `credentials` | `GitCredential` / `AccessTokenCredential` models and `CredentialStorage` ABC |
|
||||||
|
| `ssh_key` | `SshKeyPair` model and `SshKeyLifecycle` (Ed25519 generation via `cryptography`) |
|
||||||
|
| `connection` | `RepositoryConnection` ORM mapping and `ConnectionManager` orchestration |
|
||||||
|
| `operations` | Abstract `GitOperations` and concrete `LocalGitOperations` (subprocess-based `get_status`) |
|
||||||
|
|
||||||
|
Security rules for the package:
|
||||||
|
- Credential models store **only** `encrypted_payload` — no plaintext `token` or `private_key` fields.
|
||||||
|
- SSH private keys are encrypted before storage; the field uses `repr=False`.
|
||||||
|
- Real encryption of the payload is deferred to FN-009; the current placeholder is base64-only.
|
||||||
|
|||||||
Reference in New Issue
Block a user