feat(installer): build worker source over SSH
Все проверки выполнены успешно
CI / test (push) Successful in 3m13s
Docker / Build and publish worker image (push) Successful in 10m35s
Все проверки выполнены успешно
CI / test (push) Successful in 3m13s
Docker / Build and publish worker image (push) Successful in 10m35s
Этот коммит содержится в:
@@ -2,6 +2,88 @@
|
||||
|
||||
## 2026-08-12
|
||||
|
||||
### Source-install hardening review
|
||||
|
||||
- Fail-closed remote scripts: checkout, branch resolution, and build steps now
|
||||
run under `set -eu` (and package/record steps chain with `&&`), so a failed
|
||||
checkout or fetch can never be masked by a stale `rev-parse` or subsequent
|
||||
command. The checkout step additionally refuses (`git diff --quiet` /
|
||||
`--cached --quiet`) before the destructive `checkout -B`, because `-B`
|
||||
silently discards local changes and would otherwise never fail on a dirty
|
||||
tree. A dirty-tree checkout failure surfaces as a `check out branch` error
|
||||
before the build runs; the new `TestSourceInstallSSHCheckoutFailureNotMasked`
|
||||
unit test and `TestSourceInstallDirtyCheckoutPreservesStaging` Docker test
|
||||
prove the previous staging binary and commit record are preserved
|
||||
byte-for-byte.
|
||||
- Atomic toolchain replacement: the Go toolchain is downloaded, SHA-256
|
||||
verified, extracted into a same-filesystem staging dir, verified to report
|
||||
the target version, and only then swapped into `ToolchainDir` with the prior
|
||||
toolchain moved to a sibling `.go-backup` that is restored on swap failure.
|
||||
A failed download/verify/extract/swap never destroys the prior Go.
|
||||
- Record-after-build pairing: `rsmon-worker.commit` is written only after a
|
||||
successful build, so the record and the staged binary always correspond to
|
||||
the same commit. The build verifies `<stage>.new --version` before an atomic
|
||||
`mv -f` over the previous staging binary; `GOMODCACHE` is now set alongside
|
||||
`GOCACHE` inside the build dir so reruns reuse both caches.
|
||||
- Origin verification: an existing checkout's `remote.origin.url` must exactly
|
||||
match the configured repository before anything is fetched or built.
|
||||
- Repository hardening: only `https://` clone URLs without userinfo are
|
||||
accepted (`ValidateRepoURL`, enforced before dialing and again when
|
||||
planning).
|
||||
- Explicit charset validation for Go version and architecture overrides
|
||||
(`sshinstall.ValidGoVersion` / `ValidGoArch`) before any remote mutation.
|
||||
- Bounded remote execution: each remote command is capped by
|
||||
`--session-timeout` (default 30m) and captured stdout is size-bounded
|
||||
alongside the existing stderr bound; deploy's streaming `runRemote` keeps its
|
||||
historical no-timeout behavior.
|
||||
- The source installer now defaults to the remote's default branch (the public
|
||||
repo publishes `master`) instead of the plan's stale `main` default, while
|
||||
`--branch` still pins an explicit branch that must exist remotely. The
|
||||
README quickstart no longer shows the incorrect `--branch main`.
|
||||
- CLI secret flags keep their compatibility, but docs now explicitly state that
|
||||
file options (`-password-file`, etc.) keep secrets out of argv and shell
|
||||
history while direct flags expose them through the process list.
|
||||
- The harness accepts `RSMON_TEST_DOCKER_DNS` (comma-separated) to pin
|
||||
`docker run --dns` for fixture containers, so internet-facing installs are
|
||||
not at the mercy of a flaky local resolver.
|
||||
|
||||
### Remote source-install execution (work package 3)
|
||||
|
||||
- Added `installer.SourceInstall` (`internal/installer/sourceinstall.go`):
|
||||
executes the source-install flow through the existing SSH transport,
|
||||
reusing the `deploy` command's `SSHOptions` (keys, passphrases,
|
||||
passwords, sudo passwords, known-hosts, pinned fingerprints) and its
|
||||
privilege path. Extracted the shared `SSHOptions` struct and a
|
||||
`sudoWrap` helper so deploy and source install cannot diverge.
|
||||
- Steps implemented: minimal package-prerequisite install per distro
|
||||
(`apk`/`apt`/`pacman`/`dnf`, never a compiler), SHA-256-verified Go 1.26
|
||||
toolchain download/extraction with an idempotent version-skip and temp-dir
|
||||
cleanup, clone-or-update of the public repository (with a bounded 3-attempt
|
||||
retry for transient DNS/TLS/proxy failures), resolution of the remote
|
||||
default branch (a pinned branch must exist remotely), a resolved branch and
|
||||
commit record at `<BuildDir>/rsmon-worker.commit`, and a staging build
|
||||
(`CGO_ENABLED=0`, `-trimpath`, repository `-ldflags`) verified via
|
||||
`--version`. The running service, config, and data directory are untouched
|
||||
(work package 4 boundary).
|
||||
- Security: every interpolated remote value is single-quoted; branch and
|
||||
commit values are strictly validated; no worker token or control-plane
|
||||
credential is sent; sudo passwords travel only over session stdin; remote
|
||||
errors are bounded (stderr truncated in `runRemoteOutput`).
|
||||
- Added unit tests for the remote scripts, option validation, branch/commit
|
||||
parsing, sudo wrapping, the secrets-absent contract, and an in-process
|
||||
real-SSH orchestration flow (with missing-pinned-branch, build-failure, and
|
||||
detection-failure paths).
|
||||
- Added `TestSourceInstallFixtures` to the Docker/OpenSSH harness: each of
|
||||
Alpine, Ubuntu, and Arch installs from a clean state through the real
|
||||
harness transport (prerequisite install, verified Go 1.26, clone, resolved
|
||||
commit, staging build), then a rerun proves idempotency (same branch,
|
||||
toolchain reuse, no temp leaks). All three resolved the public repo's
|
||||
`master` at `4651deb2...` in the recorded run. `make test-ssh` timeout
|
||||
raised to 60m.
|
||||
- Documented the branch-resolution reality: the public repository currently
|
||||
publishes `master`, and the installer records whatever the remote default
|
||||
branch resolves to.
|
||||
|
||||
### Source-install harness and planning foundations (work packages 1-2)
|
||||
|
||||
- Added `internal/installer/harness`: a reusable Docker/OpenSSH test harness
|
||||
|
||||
Ссылка в новой задаче
Block a user