docs(openspec): archive fpagent-release-installer and sync specs
This commit is contained in:
+136
@@ -0,0 +1,136 @@
|
||||
# fpagent-installer Specification
|
||||
|
||||
## Purpose
|
||||
|
||||
Lets a field laptop install the latest private `fpagent` release with a single
|
||||
public command, without ever handling the forge credential — the tools app
|
||||
proxies the private release and serves the installer.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Public installer endpoint
|
||||
|
||||
The app SHALL serve an installer script at `/fpagent/install.sh` that is
|
||||
reachable without authentication. When run, the script SHALL fetch the latest
|
||||
release metadata, choose a bundle for the host, verify the bundle's published
|
||||
sha256 checksum, extract it, and hand off to the extracted bundle's own
|
||||
installer. The script SHALL be served uncached.
|
||||
|
||||
#### Scenario: Installer is fetched anonymously
|
||||
|
||||
- **WHEN** a client requests `/fpagent/install.sh` without a session
|
||||
- **THEN** the app returns the installer script and does not redirect to login
|
||||
|
||||
#### Scenario: Host-appropriate bundle is chosen
|
||||
|
||||
- **WHEN** the latest release offers both a bundle for the host's Ubuntu
|
||||
codename and a generic bundle
|
||||
- **THEN** the installer uses the codename bundle
|
||||
|
||||
#### Scenario: Generic bundle is the fallback
|
||||
|
||||
- **WHEN** the latest release offers no bundle matching the host's Ubuntu
|
||||
codename
|
||||
- **THEN** the installer uses the generic bundle
|
||||
|
||||
#### Scenario: Checksum is verified before extraction
|
||||
|
||||
- **WHEN** the installer downloads a bundle and its published checksum
|
||||
- **THEN** it verifies the checksum before extracting and refuses to install
|
||||
when the checksum does not match
|
||||
|
||||
#### Scenario: Options are forwarded to the bundled installer
|
||||
|
||||
- **WHEN** the installer is invoked with options such as `--enable-service` or
|
||||
`--check`
|
||||
- **THEN** it passes those options through to the extracted bundle's installer
|
||||
|
||||
#### Scenario: No compatible bundle
|
||||
|
||||
- **WHEN** the latest release contains no bundle for the host architecture
|
||||
- **THEN** the installer exits with a failure message and installs nothing
|
||||
|
||||
### Requirement: Release metadata endpoint
|
||||
|
||||
The app SHALL expose a same-origin endpoint that returns the latest release's
|
||||
tag and the names of its downloadable assets as same-origin URLs. The app SHALL
|
||||
authenticate to the private forge using the configured release key, SHALL omit
|
||||
asset names that are not valid asset names, and SHALL NOT reveal the release
|
||||
key or the forge host to clients.
|
||||
|
||||
#### Scenario: Latest release is returned
|
||||
|
||||
- **WHEN** a client requests the latest-release endpoint and the forge returns
|
||||
a release
|
||||
- **THEN** the response carries the release tag and each asset's name and a
|
||||
same-origin URL under `/fpagent/releases/download/`
|
||||
|
||||
#### Scenario: Unsafe asset names are omitted
|
||||
|
||||
- **WHEN** the forge release lists an asset whose name is not a valid asset
|
||||
name
|
||||
- **THEN** that asset does not appear in the response
|
||||
|
||||
#### Scenario: Release key is not exposed
|
||||
|
||||
- **WHEN** any client fetches the latest-release endpoint
|
||||
- **THEN** the response body contains neither the release key nor the forge host
|
||||
|
||||
#### Scenario: Installer not configured
|
||||
|
||||
- **WHEN** the release key is not configured
|
||||
- **THEN** the endpoint answers that the installer is not configured
|
||||
|
||||
#### Scenario: Forge unavailable
|
||||
|
||||
- **WHEN** the forge cannot be reached or returns an error for the latest
|
||||
release
|
||||
- **THEN** the endpoint answers with a gateway error
|
||||
|
||||
### Requirement: Release asset download proxy
|
||||
|
||||
The app SHALL stream a requested release asset to the client through a
|
||||
same-origin route, authenticating the upstream request with the release key so
|
||||
the client sends no credentials. It SHALL reject asset names that are not valid
|
||||
asset names and SHALL report a missing asset as not found.
|
||||
|
||||
#### Scenario: Asset is streamed without client credentials
|
||||
|
||||
- **WHEN** a client requests a release asset by tag and name without any
|
||||
credential
|
||||
- **THEN** the app fetches it from the forge with the release key and streams
|
||||
its bytes to the client
|
||||
|
||||
#### Scenario: Invalid asset name is rejected
|
||||
|
||||
- **WHEN** a client requests an asset whose tag or name is not a valid asset
|
||||
name
|
||||
- **THEN** the app rejects the request without contacting the forge
|
||||
|
||||
#### Scenario: Missing asset
|
||||
|
||||
- **WHEN** the forge reports the requested asset as not found
|
||||
- **THEN** the app answers with not found
|
||||
|
||||
#### Scenario: Installer not configured
|
||||
|
||||
- **WHEN** the release key is not configured
|
||||
- **THEN** the endpoint answers that the installer is not configured
|
||||
|
||||
### Requirement: Installer credential stays server-side
|
||||
|
||||
The app SHALL read the private-forge release key from the
|
||||
`GITEA_RELEASE_INSTALL_KEY` environment variable. The key SHALL NOT appear in
|
||||
the installer script, in any release metadata response, or in any streamed
|
||||
asset.
|
||||
|
||||
#### Scenario: Served installer carries no credential
|
||||
|
||||
- **WHEN** a client fetches `/fpagent/install.sh`
|
||||
- **THEN** the response contains no release key
|
||||
|
||||
#### Scenario: Credential supplied by the environment
|
||||
|
||||
- **WHEN** the release key is supplied in the environment
|
||||
- **THEN** the installer and proxy endpoints use it without any change to the
|
||||
hardcoded configuration
|
||||
Reference in New Issue
Block a user