Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ This repository uses a single Go module at the root, with two binaries:

| Path | Purpose |
|---|---|
| `cmd/harbor-satellite/` | Satellite edge daemon - CLI, config, registry, state replication |
| `cmd/ground-control/` | Ground Control cloud service - satellite management, Harbor integration, PostgreSQL |
| `cmd/satellite/` | Satellite edge daemon - CLI, config, registry, state replication |
| `cmd/groundcontrol/` | Ground Control cloud service (server and CLI) - satellite management, Harbor integration, PostgreSQL |

Run all Go commands from the repository root.

Expand All @@ -48,10 +48,10 @@ task _build:satellite
task _build:ground-control

# Run the satellite directly
go run cmd/harbor-satellite/main.go --token "<token>" --ground-control-url "http://127.0.0.1:8080"
go run cmd/satellite/main.go --token "<token>" --ground-control-url "http://127.0.0.1:8080"

# Run Ground Control directly (requires a configured .env file)
go run cmd/ground-control/main.go
go run cmd/groundcontrol/server/main.go
```

For Ground Control local setup, copy `.env.example` to `.env` and fill in the required values.
Expand Down
2 changes: 1 addition & 1 deletion cmd/groundcontrol/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (
"syscall"
"time"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/harborhealth"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/migrator"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/server"
"github.com/container-registry/harbor-satellite/internal/shared/env"
"github.com/joho/godotenv"
)

Expand Down
2 changes: 1 addition & 1 deletion cmd/satellite/audit_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"testing"

"github.com/container-registry/harbor-satellite/internal/logger"
"github.com/container-registry/harbor-satellite/internal/shared/logger"
"github.com/container-registry/harbor-satellite/pkg/config"
"github.com/stretchr/testify/require"
)
Expand Down
6 changes: 3 additions & 3 deletions cmd/satellite/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import (
"os"
"time"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/logger"
"github.com/container-registry/harbor-satellite/internal/satellite"
runtime "github.com/container-registry/harbor-satellite/internal/satellite/container_runtime"
"github.com/container-registry/harbor-satellite/internal/satellite/events"
"github.com/container-registry/harbor-satellite/internal/satellite/hotreload"
"github.com/container-registry/harbor-satellite/internal/satellite/watcher"
"github.com/container-registry/harbor-satellite/internal/utils"
"github.com/container-registry/harbor-satellite/internal/shared/env"
"github.com/container-registry/harbor-satellite/internal/shared/logger"
"github.com/container-registry/harbor-satellite/internal/shared/utils"
"github.com/container-registry/harbor-satellite/pkg/config"

"github.com/joho/godotenv"
Expand Down
16 changes: 8 additions & 8 deletions docs/decisions/0005-spiffe-identity-and-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ sequenceDiagram

### 5. Satellite SPIFFE Client

File: `internal/spiffe/client.go`
File: `internal/shared/spiffe/client.go`

- Connects to SPIRE agent via Workload API socket (embedded or external)
- Obtains X.509 SVID, creates mTLS HTTP client
Expand All @@ -234,7 +234,7 @@ sequenceDiagram
### 6. Embedded SPIRE Agent in Satellite (Phase 1 - TO IMPLEMENT)

- Mirror the pattern from GC's `embedded_server.go`
- Create `internal/spiffe/embedded_agent.go`: subprocess manager for `spire-agent run`
- Create `internal/shared/spiffe/embedded_agent.go`: subprocess manager for `spire-agent run`
- Start/stop with readiness polling, graceful shutdown
- Config generation: trust domain, attestation method
- SPIRE server address must be explicitly configured (no assumption that GC runs the server)
Expand Down Expand Up @@ -307,7 +307,7 @@ spiffe://<trust-domain>/satellite/region/<region>/<name>
### 11. Device Identity and Config Encryption

- `internal/identity/device_linux.go`: SHA-256 fingerprint from machine-id + MAC + disk serial
- `internal/crypto/aes_provider.go`: AES-256-GCM, Argon2id key derivation (OWASP 2024)
- `internal/shared/crypto/aes_provider.go`: AES-256-GCM, Argon2id key derivation (OWASP 2024)
- `internal/secure/config.go`: encrypted config-at-rest, version 1 envelope
- Device-bound: config cannot migrate between machines
- Encryption must work in ALL builds (currently broken in nospiffe build tag; must be decoupled)
Expand Down Expand Up @@ -439,12 +439,12 @@ sequenceDiagram
## Source Files

- `internal/satellite/satellite.go:35-55` - ZTR path selection
- `internal/state/spiffe_registration.go` - SPIFFE ZTR process
- `internal/state/registration_process.go` - Token ZTR process
- `internal/spiffe/client.go` - Workload API client
- `internal/satellite/state/spiffe_registration.go` - SPIFFE ZTR process
- `internal/satellite/state/registration_process.go` - Token ZTR process
- `internal/shared/spiffe/client.go` - Workload API client
- `internal/identity/device_linux.go` - Device fingerprinting
- `internal/crypto/aes_provider.go` - AES encryption
- `internal/crypto/provider_stub.go` - nospiffe stub (no-op)
- `internal/shared/crypto/aes_provider.go` - AES encryption
- `internal/shared/crypto/provider_stub.go` - nospiffe stub (no-op)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- `internal/identity/device_stub.go` - nospiffe stub (errors)
- `internal/secure/config.go` - Config encryption wrapper
- `pkg/config/manager.go` - EncryptConfig flag, write logic
Expand Down
6 changes: 3 additions & 3 deletions docs/decisions/0007-security-plugins-parsec.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ internal/parsec/

### `KeyProvider` implements `crypto.Provider`

`KeyProvider` implements the existing `internal/crypto.Provider` interface so it can be swapped
`KeyProvider` implements the existing `internal/shared/crypto.Provider` interface so it can be swapped
into `pkg/config/manager.go` without changes to any downstream consumer.

The key design challenge is that `crypto.Provider.Sign(data []byte, key crypto.PrivateKey)`
Expand Down Expand Up @@ -193,7 +193,7 @@ In Phase 2, `Signer` is used as the private key for SPIRE's `tpm_devid` node att
This makes the SPIRE agent's attestation to the SPIRE server hardware-rooted: Ground Control's
trust in the satellite is cryptographically bound to the physical device.

The existing `workloadapi.X509Source` SVID delivery flow in `internal/spiffe/client.go` is
The existing `workloadapi.X509Source` SVID delivery flow in `internal/shared/spiffe/client.go` is
unaffected — PARSEC operates below the SVID layer.

```
Expand All @@ -210,7 +210,7 @@ PARSEC (hardware key) → SPIRE tpm_devid (node attestation) → SVID issuance

Target coverage (not all of these exist yet; see Phase-1 Limitations below):

- Unit tests for `KeyProvider` using a mock PARSEC client (same pattern as `internal/crypto/mock.go`)
- Unit tests for `KeyProvider` using a mock PARSEC client (same pattern as `internal/shared/crypto/mock.go`)
- `parsec` build tag compiles cleanly alongside `nospiffe` and default builds
- Default build (no `parsec` tag) continues to pass all existing tests unchanged
- E2E test (`test-parsec` task in `taskfiles/e2e.yml`) using a real PARSEC daemon in CI,
Expand Down
22 changes: 10 additions & 12 deletions docs/decisions/ground-control-internal-package-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,25 @@ harbor-satellite/
├── internal/
│ ├── satellite/
│ ├── groundcontrol/
│ ├── auth/
│ ├── database/
│ ├── harborhealth/
│ ├── middleware/
│ ├── models/
│ ├── server/
│ ├── spiffe/
│ ├── logger/
│ ├── crypto/
│ ├── shared/
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
│ │ ├── crypto/
│ │ ├── env/
│ │ ├── logger/
│ │ ├── spiffe/
│ │ └── utils/
│ └── ...
├── pkg/
└── go.mod
```
> **Note:** This layout has been superseded by issue #593.

## Design Guidelines

- Keep exactly one Go module at the repository root.
- Move executable entrypoints into `cmd/<binary-name>/main.go`.
- Keep `cmd` packages thin. They should only parse configuration, initialize dependencies, and call internal application code.
- Prefer `internal/satellite` and `internal/groundcontrol` for binary-specific application logic.
- Avoid a generic `internal/shared` package. Shared code should live in packages named after the behavior or domain they own, such as `internal/logger`, `internal/spiffe`, `internal/auth`, or `internal/database`.
- Prefer `internal/satellite` and `internal/groundcontrol` for binary-specific application logic (such as `internal/groundcontrol/auth` or `internal/groundcontrol/database`).
- Avoid a generic catch-all package under `internal/shared`. Shared code should live in packages named after the behavior or domain they own, such as `internal/shared/logger`, `internal/shared/spiffe`, `internal/shared/crypto`, or `internal/shared/env`.
- Keep code in `pkg` only when it is intentionally public and stable for external consumers. Code used only by repository binaries should live under `internal`.

## Migration Plan
Expand All @@ -59,7 +57,7 @@ harbor-satellite/
### Phase 2: Refactor Satellite Internal Packages

- [x] Move satellite-specific packages from `internal/*` into `internal/satellite/*`.
- [x] Keep cross-cutting packages used by both binaries at the root of `internal`.
- [x] Keep cross-cutting packages used by both binaries under `internal/shared/*`.
- [x] Update satellite imports to use `github.com/container-registry/harbor-satellite/internal/satellite/...`.
- [x] Run satellite package tests from the root module.

Expand Down
6 changes: 3 additions & 3 deletions docs/decisions/security-parsec-integration-draft.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ PARSEC and SPIRE are **complementary, not competing**:
| Workload identity | SPIRE | Issues X.509 SVIDs after attestation succeeds |
| mTLS & ZTR | Existing SPIFFE client | Unchanged — receives SVID and uses it for mTLS with Ground Control |

PARSEC plugs into SPIRE at the **node attestation layer**. The existing `internal/spiffe/client.go`
PARSEC plugs into SPIRE at the **node attestation layer**. The existing `internal/shared/spiffe/client.go`
SVID delivery flow is unaffected. This maps directly onto ADR-0005's explicit roadmap:

- **Phase 2** (planned): TPM-based node attestation via SPIRE `tpm_devid` plugin — PARSEC enables this
Expand Down Expand Up @@ -139,7 +139,7 @@ internal/parsec/
provider_stub.go # no-op stubs, same shape as spiffe/client_stub.go [!parsec]
```

All files under `internal/parsec/` follow the same build tag pattern as `internal/spiffe/`:
All files under `internal/parsec/` follow the same build tag pattern as `internal/shared/spiffe/`:
`//go:build parsec` for real implementations, `//go:build !parsec` for stubs. Default builds
compile to zero PARSEC dependency.

Expand Down Expand Up @@ -253,7 +253,7 @@ core PARSEC integration and should be designed independently.

### Tests needed

- Unit tests for `KeyProvider` using a mock PARSEC client (same pattern as `internal/crypto/mock.go`)
- Unit tests for `KeyProvider` using a mock PARSEC client (same pattern as `internal/shared/crypto/mock.go`)
- E2E test similar to `TestSpiffeJoinTokenE2E` that exercises the full flow with a real PARSEC
daemon in CI (the `parsec-client-go` repo has a Docker-based test harness that can be reused)

Expand Down
11 changes: 6 additions & 5 deletions docs/guides/ground-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

Ground Control is the cloud-side management service for Harbor Satellite. It manages satellites, groups, configs, registration, desired state, status reporting, and Harbor integration.

Ground Control is part of the single Go module at the repository root. Its code lives under `internal/groundcontrol/` with the entrypoint in `cmd/ground-control/main.go`. Run all Go commands from the repository root.
Ground Control is part of the single Go module at the repository root. Its code lives under `internal/groundcontrol/` with the entrypoint in `cmd/groundcontrol/server/main.go`. Run all Go commands from the repository root.

## What It Starts

`cmd/ground-control/main.go` performs the Ground Control startup sequence:
`cmd/groundcontrol/server/main.go` performs the Ground Control startup sequence:

- Checks Harbor health
- Runs PostgreSQL migrations
Expand All @@ -22,7 +22,7 @@ Populate the required environment variables first. For local development, use `.
Run Ground Control locally from the repository root:

```bash
go run cmd/ground-control/main.go
go run cmd/groundcontrol/server/main.go
```

Run Ground Control tests:
Expand Down Expand Up @@ -59,7 +59,8 @@ Key groups include:

## Directory Guide

- `cmd/ground-control/main.go` - service entrypoint
- `cmd/groundcontrol/server/main.go` - service entrypoint
- `cmd/groundcontrol/cli/root.go` - CLI entrypoint
- `internal/groundcontrol/server` - routes, handlers, auth middleware, bootstrap, cleanup, and status APIs
- `internal/groundcontrol/database` - sqlc-generated database access code
- `internal/groundcontrol/sql/schema` - PostgreSQL migrations
Expand All @@ -68,7 +69,7 @@ Key groups include:
- `internal/groundcontrol/harbor` - Harbor API client helpers
- `internal/groundcontrol/spiffe` - SPIFFE/SPIRE provider and server client integration
- `internal/groundcontrol/auth` - password policy and hashing helpers
- `internal/crypto` - shared crypto helpers used by Ground Control
- `internal/shared/crypto` - shared crypto helpers used by Ground Control

## Related Docs

Expand Down
2 changes: 1 addition & 1 deletion internal/groundcontrol/auth/password.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"encoding/base64"
"fmt"

"github.com/container-registry/harbor-satellite/internal/crypto"
"github.com/container-registry/harbor-satellite/internal/shared/crypto"
)

// HashPassword creates an Argon2id hash of the password.
Expand Down
2 changes: 1 addition & 1 deletion internal/groundcontrol/auth/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"strings"
"unicode"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/shared/env"
)

type PasswordPolicy struct {
Expand Down
2 changes: 1 addition & 1 deletion internal/groundcontrol/auth/policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package auth
import (
"testing"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/shared/env"
"github.com/stretchr/testify/require"
)

Expand Down
2 changes: 1 addition & 1 deletion internal/groundcontrol/harbor/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package harbor
import (
"sync"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/shared/env"
"github.com/goharbor/go-client/pkg/harbor"
v2client "github.com/goharbor/go-client/pkg/sdk/v2.0/client"
)
Expand Down
2 changes: 1 addition & 1 deletion internal/groundcontrol/harbor/robot.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"fmt"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/shared/env"
"github.com/goharbor/go-client/pkg/sdk/v2.0/client/robot"
"github.com/goharbor/go-client/pkg/sdk/v2.0/models"
)
Expand Down
2 changes: 1 addition & 1 deletion internal/groundcontrol/harbor/robot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package harbor
import (
"testing"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/shared/env"
"github.com/stretchr/testify/require"
)

Expand Down
2 changes: 1 addition & 1 deletion internal/groundcontrol/harborhealth/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"net/url"
"time"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/shared/env"
)

type config struct {
Expand Down
2 changes: 1 addition & 1 deletion internal/groundcontrol/migrator/migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"os"
"time"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/shared/env"
_ "github.com/lib/pq"
"github.com/pressly/goose/v3"
)
Expand Down
4 changes: 2 additions & 2 deletions internal/groundcontrol/server/audit_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package server
import (
"testing"

"github.com/container-registry/harbor-satellite/internal/env"
auditlog "github.com/container-registry/harbor-satellite/internal/groundcontrol/logger"
"github.com/container-registry/harbor-satellite/internal/shared/env"
auditlog "github.com/container-registry/harbor-satellite/internal/shared/logger"
"github.com/stretchr/testify/require"
)

Expand Down
2 changes: 1 addition & 1 deletion internal/groundcontrol/server/auth_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (

"github.com/container-registry/harbor-satellite/internal/groundcontrol/auth"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/database"
auditlog "github.com/container-registry/harbor-satellite/internal/groundcontrol/logger"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/spiffe"
auditlog "github.com/container-registry/harbor-satellite/internal/shared/logger"
)

const maxFailedAttempts = 5
Expand Down
2 changes: 1 addition & 1 deletion internal/groundcontrol/server/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"fmt"
"log"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/auth"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/database"
"github.com/container-registry/harbor-satellite/internal/shared/env"
)

const systemAdminUsername = "admin"
Expand Down
4 changes: 2 additions & 2 deletions internal/groundcontrol/server/config_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
"reflect"
"strings"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/database"
auditlog "github.com/container-registry/harbor-satellite/internal/groundcontrol/logger"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/utils"
"github.com/container-registry/harbor-satellite/internal/shared/env"
auditlog "github.com/container-registry/harbor-satellite/internal/shared/logger"
jsonpatch "github.com/evanphx/json-patch"
"github.com/lib/pq"
)
Expand Down
2 changes: 1 addition & 1 deletion internal/groundcontrol/server/group_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (
"log"
"net/http"

"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/database"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/harbor"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/utils"
"github.com/container-registry/harbor-satellite/internal/shared/env"
)

func (s *Server) SyncGroup(w http.ResponseWriter, r *http.Request) {
Expand Down
4 changes: 2 additions & 2 deletions internal/groundcontrol/server/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import (
"strings"
"time"

"github.com/container-registry/harbor-satellite/internal/crypto"
"github.com/container-registry/harbor-satellite/internal/env"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/database"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/harbor"
"github.com/container-registry/harbor-satellite/internal/groundcontrol/utils"
"github.com/container-registry/harbor-satellite/internal/shared/crypto"
"github.com/container-registry/harbor-satellite/internal/shared/env"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/crane"
)
Expand Down
Loading
Loading