Compare commits

..
2 Commits
Author SHA1 Message Date
spacesops d054ba22c9 1.0.4:0 2026-08-25 16:54:57 -04:00
spacesops d026857b99 pre 2026-08-25 16:20:05 -04:00
20 changed files with 1472 additions and 264 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
# spacesops ships linux/amd64 + linux/arm64 only (no riscv), so build both.
ARCHES := x86 arm
# overrides to s9pk.mk must precede the include statement
include s9pk.mk
include node_modules/@start9labs/start-sdk/s9pk.mk
+40 -21
View File
@@ -39,7 +39,9 @@ auto-connects to it — see [Installation and First-Run Flow](#installation-and-
| Field | Value |
| --- | --- |
| Image | `docker.io/spacesops/spacesops:v1.0.1` |
| Package version | `1.0.4:0` |
| Requires | StartOS `0.4.0-beta.10` or later (built with `@start9labs/start-sdk` 2.x) |
| Image | `docker.io/spacesops/spacesops:v1.0.4` |
| Base | `node:20-alpine` |
| Architectures | `x86_64` (linux/amd64), `aarch64` (linux/arm64) |
| Entrypoint | The image's `/app/docker-entrypoint.sh` is **kept**. StartOS runs `/app/docker-entrypoint.sh node server.js` as the daemon. |
@@ -86,7 +88,7 @@ credentials. Instead, at startup it:
2. Reads `spacedAuth.{username,password}` from the Spaces `store.json`.
3. Connects to spaced at `http://spaces.startos:7225` with those credentials,
exporting `SPACED_RPC_URL`, `SPACED_RPC_USER`, `SPACED_RPC_PASSWORD`, and
`SPACED_WALLETLOAD_NAME=main`.
`SPACED_WALLETLOAD_NAME=default`.
If Spaces is not installed yet, or its credentials have not been seeded, the
service **restarts until they appear** — this is expected. (Dependency
@@ -101,13 +103,18 @@ declarations do not gate startup; SpacesOps handles readiness itself.)
| `OPERATOR_SECRET_HEX` / `OPERATOR_PUBLIC_HEX` (generated or imported) | |
| `PLATFORM_SESSION_SECRET` (generated) | |
| `SPACED_RPC_*` (auto-wired from Spaces) | |
| `PLATFORM_CALLBACK_HOST` (defaults to `spacesops.startos`; override via **Configure Platform**) | |
| Optional: `OPERATOR_RELAY`, `PLATFORM_MODE`, `COINGECKO_*`, `SUBS_*` (via **Configure Platform**) | |
## Network Access and Interfaces
| Interface | Port | Protocol | Exposure | Notes |
| Interface | Port | Protocol | Type | Notes |
| --- | --- | --- | --- | --- |
| Web UI | 7264 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | The SpacesOps web platform + admin area. The app provides its own auth; the admin area uses a **fixed built-in credential** (see warning below). |
| Web UI | 7264 | HTTP | `ui` | The SpacesOps web platform + admin area. The app provides its own auth; the admin area uses a **fixed built-in credential** (see warning below). |
The package binds port 7264 and exports a single `ui` interface. **Where that
interface is reachable is the user's choice**, made in StartOS — the package
neither provisions nor implies any particular address.
## Actions
@@ -116,7 +123,7 @@ declarations do not gate startup; SpacesOps handles readiness itself.)
| `show-operator-credentials` | Show Operator Credentials | Enabled | Any | — | Displays the Nostr operator keypair: npub (QR), hex public key, and the masked nsec / hex secret. |
| `import-operator-key` | Import Operator Key | Enabled | Any | 64-char hex secret key | Replaces the operator keypair. Derives the public key automatically. **Warns** that it changes the operator identity; the service restarts to apply it. |
| `show-admin-credentials` | Show Admin Credentials | Enabled | Any | — | Displays the **fixed** built-in admin login (`admin` / `Whatever!`) with a security warning. |
| `configure-platform` | Configure Platform | Enabled | Any | relay, mode, CoinGecko, SUBS (all optional) | Sets the Nostr relay, theme mode, pricing, and SUBS backend. Saving restarts the service. |
| `configure-platform` | Configure Platform | Enabled | Any | relay, mode, CoinGecko, SUBS, callback host | Sets the Nostr relay, theme mode, pricing, SUBS backend, and `PLATFORM_CALLBACK_HOST`. Saving restarts the service. |
## Backups and Restore
@@ -138,24 +145,31 @@ volume is **not** part of this package's backup.
by reading the Spaces RPC credentials from the mounted Spaces volume. Install
and sync Spaces before (or alongside) SpacesOps; the service restarts until
those credentials are available.
2. **The admin password is fixed and well-known.** Admin Basic Auth is hardcoded
in the v1.0.1 image as `admin` / `Whatever!` with **no environment override**.
It cannot be changed without rebuilding the image. **Keep this service private
(Tor-only) and never expose its admin routes to the public internet** — the
admin area can run SQL and manage tenants. See **Show Admin Credentials**.
2. **The admin password is well-known.** The app resolves admin Basic Auth as
`process.env.PLATFORM_ADMIN_USERNAME || 'admin'` and
`process.env.PLATFORM_ADMIN_PASSWORD || 'Whatever!'`. This package does not
currently set either variable, so the well-known defaults are live. **Keep
this service private and do not make its admin routes broadly reachable** —
the admin area can run SQL and manage tenants. See **Show Admin
Credentials**. Setting `PLATFORM_ADMIN_PASSWORD` to a generated secret (as
this package already does for `PLATFORM_SESSION_SECRET`) would close this
gap; see `TODO.md`.
3. **`PLATFORM_HOST` is forced to `0.0.0.0` and `PLATFORM_PORT` to `7264`** so the
StartOS reverse proxy can reach the app (it otherwise binds `127.0.0.1:3000`).
4. **Subname-purchase and pricing are off by default.** They activate only when
you fill in the relevant fields in **Configure Platform** (`COINGECKO_*` for
pricing, `SUBS_*` for subname purchase + cert-callback flows).
pricing, `SUBS_*` for subname purchase + cert-callback flows). Payment
callback URLs use `PLATFORM_CALLBACK_HOST`, which defaults to `spacesops.startos`
and can be overridden in **Configure Platform**.
5. **The SUBS backend is not auto-wired to the Spaces subs daemon in v1.** The
Spaces service's subs daemon listens on 7777 with a different API/auth than
the SUBS endpoint (port 7244) SpacesOps expects, so SUBS must be configured
manually if used. StartOS always sets `NODE_EXTRA_CA_CERTS` to the StartOS
root CA (fetched via `sdk.getSslCertificate` for the SUBS `*.startos`
hostname when configured, otherwise `spaces.startos`) so outbound HTTPS to
same-host StartOS services succeeds and the v1.0.1 image entrypoint does not
crash on its broken `_SCRIPT_DIR` default.
manually if used. StartOS always sets `NODE_EXTRA_CA_CERTS` to this box's
StartOS root CA (fetched via `sdk.getSslCertificate` for the SUBS `*.startos`
hostname when configured, otherwise `spaces.startos`). This overrides the
image's own default of `/app/certs/startos-local-root-ca.pem`, a root CA
baked in at build time from a different machine, so outbound HTTPS to
same-host StartOS services succeeds.
## What Is Unchanged from Upstream
@@ -170,8 +184,11 @@ volume is **not** part of this package's backup.
```yaml
package_id: spacesops
upstream_version: 1.0.1
image: docker.io/spacesops/spacesops:v1.0.1
package_version: 1.0.4:0
upstream_version: 1.0.4
image: docker.io/spacesops/spacesops:v1.0.4
min_startos_version: 0.4.0-beta.10
start_sdk_version: 2.0.9
architectures: [x86_64, aarch64]
volumes:
main: /data
@@ -193,7 +210,8 @@ startos_managed_env_vars:
- SPACED_RPC_URL # http://spaces.startos:7225
- SPACED_RPC_USER # from Spaces store.json
- SPACED_RPC_PASSWORD # from Spaces store.json
- SPACED_WALLETLOAD_NAME # main
- SPACED_WALLETLOAD_NAME # default
- PLATFORM_CALLBACK_HOST # store.platformCallbackHost ?? spacesops.startos
optional_env_vars: # only set when configured via configure-platform
- COINGECKO_API_KEY
- COINGECKO_TOKEN_COINS
@@ -202,8 +220,9 @@ optional_env_vars: # only set when configured via configure-platform
- SUBS_RPC_PASSWORD
- NODE_EXTRA_CA_CERTS # /data/.startos/startos-root-ca.crt (always set)
admin_credentials:
username: admin
password: Whatever! # FIXED, baked into image, cannot be changed
username: admin # app default; override via PLATFORM_ADMIN_USERNAME
password: Whatever! # app default; override via PLATFORM_ADMIN_PASSWORD
overridden_by_package: false # package does not set either var today
note: keep service private; admin area can run SQL and manage tenants
actions:
- show-operator-credentials
+42
View File
@@ -0,0 +1,42 @@
# TODO
## Set a generated admin password
The app resolves its admin Basic Auth credentials as:
```js
const ADMIN_USERNAME = process.env.PLATFORM_ADMIN_USERNAME || 'admin'
const ADMIN_PASSWORD = process.env.PLATFORM_ADMIN_PASSWORD || 'Whatever!'
```
(verified in `/app/server.js` of `spacesops/spacesops:v1.0.4`)
These are **defaults, not hardcoded values** — both are overridable via
environment variables. The package currently sets neither, so every install
ships the same publicly known admin password, guarding an area that can run SQL
and manage tenants.
The fix mirrors what the package already does for `PLATFORM_SESSION_SECRET`:
1. Add an `adminPassword` field to `fileModels/storeJson.ts`.
2. Seed it in a `setupOnInit` task with `utils.getDefaultString(...)`, the same
way `init/taskSessionSecret.ts` does.
3. Inject `PLATFORM_ADMIN_PASSWORD` (and optionally
`PLATFORM_ADMIN_USERNAME`) from the store in `main.ts`.
4. Update the **Show Admin Credentials** action to read the generated value
instead of the `ADMIN_USER` / `ADMIN_PASSWORD` constants in `utils.ts`.
5. Add a "Reset Admin Password" action (see `recipe-reset-password.md`).
6. Update `README.md` limitation 2 and the `instructions.md` admin section,
which currently document the well-known default as the live credential.
This is a behavior change for existing installs — a user who bookmarked the old
password would be locked out — so it needs release notes calling it out, and
possibly a migration that seeds the store for already-installed services.
## Verify on a live box
The 2.x SDK migration and the v1.0.4 bump have been compiled, linted, and
packed, but not yet installed and exercised on a StartOS 0.4.0-beta.10+ host.
Confirm the service starts, the web UI is reachable, the Spaces credential probe
succeeds, and outbound HTTPS to `*.startos` works with the injected
`NODE_EXTRA_CA_CERTS`.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

+5 -4
View File
@@ -24,15 +24,16 @@ SpacesOps dashboard.
## ⚠️ Admin credentials — important
The admin area is protected by a **fixed, well-known** login that is baked into
the image and **cannot be changed**:
The admin area is protected by a **well-known default** login that this version
of the package does not change:
- **Username:** `admin`
- **Password:** `Whatever!`
The **Show Admin Credentials** action displays these. Because the admin area can
run SQL and manage tenants, **keep this service private**use it over Tor or
your LAN, and do **not** expose its admin routes to the public internet.
run SQL and manage tenants, **keep this service private**restrict how you
make it reachable in StartOS, and do **not** make its admin routes broadly
accessible.
## Actions
+1310 -25
View File
File diff suppressed because it is too large Load Diff
+6 -3
View File
@@ -6,14 +6,17 @@
"check": "tsc --noEmit"
},
"dependencies": {
"@start9labs/start-sdk": "1.5.1"
"@start9labs/start-sdk": "2.0.9",
"nostr-tools": "^2.10.4"
},
"overrides": {
"@start9labs/start-sdk": "$@start9labs/start-sdk"
},
"devDependencies": {
"@types/node": "^22.19.0",
"@vercel/ncc": "^0.38.4",
"nostr-tools": "^2.10.4",
"prettier": "^3.6.2",
"typescript": "^5.9.3"
"typescript": "^6.0.3"
},
"prettier": {
"trailingComma": "all",
-141
View File
@@ -1,141 +0,0 @@
# ** Plumbing. DO NOT EDIT **.
# This file is imported by ./Makefile. Make edits there
PACKAGE_ID := $(shell awk -F"'" '/id:/ {print $$2}' startos/manifest/index.ts)
INGREDIENTS := $(shell start-cli s9pk list-ingredients 2>/dev/null)
# Resolve the actual git dir so this works inside git worktrees, where .git
# is a file pointing at <main>/.git/worktrees/<name> rather than a directory.
GIT_DIR := $(shell git rev-parse --git-dir 2>/dev/null)
GIT_DEPS := $(if $(GIT_DIR),$(GIT_DIR)/HEAD $(GIT_DIR)/index)
ARCHES ?= x86 arm riscv
# TARGETS is the list of leaf make-targets the build matrix fans out over.
# Defaults to the arches; variant packages override (e.g. immich, ollama, vllm
# set this to a list of variant or variant-arch leaf targets).
TARGETS ?= $(ARCHES)
ifdef VARIANT
BASE_NAME := $(PACKAGE_ID)_$(VARIANT)
else
BASE_NAME := $(PACKAGE_ID)
endif
.PHONY: all arches aarch64 x86_64 riscv64 arm arm64 x86 riscv arch/* clean install check-deps check-init package ingredients
.DELETE_ON_ERROR:
.SECONDARY:
define SUMMARY
@manifest=$$(start-cli s9pk inspect $(1) manifest); \
size=$$(du -h $(1) | awk '{print $$1}'); \
title=$$(printf '%s' "$$manifest" | jq -r .title); \
version=$$(printf '%s' "$$manifest" | jq -r .version); \
arches=$$(printf '%s' "$$manifest" | jq -r '[.images[].arch // []] | flatten | unique | join(", ")'); \
sdkv=$$(printf '%s' "$$manifest" | jq -r .sdkVersion); \
gitHash=$$(printf '%s' "$$manifest" | jq -r .gitHash | sed -E 's/(.*-modified)$$/\x1b[0;31m\1\x1b[0m/'); \
printf "\n"; \
printf "\033[1;32m✅ Build Complete!\033[0m\n"; \
printf "\n"; \
printf "\033[1;37m📦 $$title\033[0m \033[36mv$$version\033[0m\n"; \
printf "───────────────────────────────\n"; \
printf " \033[1;36mFilename:\033[0m %s\n" "$(1)"; \
printf " \033[1;36mSize:\033[0m %s\n" "$$size"; \
printf " \033[1;36mArch:\033[0m %s\n" "$$arches"; \
printf " \033[1;36mSDK:\033[0m %s\n" "$$sdkv"; \
printf " \033[1;36mGit:\033[0m %s\n" "$$gitHash"; \
echo ""
endef
all: $(TARGETS)
arches: $(ARCHES)
# Generic make-variable introspection. Used by the release workflow to
# read $(TARGETS) and fan out one matrix runner per target. `make -s
# print-TARGETS` echoes the list with no other output.
print-%:
@echo '$($*)'
universal: $(BASE_NAME).s9pk
$(call SUMMARY,$<)
arch/%: $(BASE_NAME)_%.s9pk
$(call SUMMARY,$<)
x86 x86_64: arch/x86_64
arm arm64 aarch64: arch/aarch64
riscv riscv64: arch/riscv64
$(BASE_NAME).s9pk: $(INGREDIENTS) $(GIT_DEPS)
@$(MAKE) --no-print-directory ingredients
@echo " Packing '$@'..."
start-cli s9pk pack -o $@
$(BASE_NAME)_%.s9pk: $(INGREDIENTS) $(GIT_DEPS)
@$(MAKE) --no-print-directory ingredients
@echo " Packing '$@'..."
start-cli s9pk pack --arch=$* -o $@
ingredients: $(INGREDIENTS)
@echo " Re-evaluating ingredients..."
install: | check-deps check-init
@HOST=$$(awk -F'/' '/^host:/ {print $$3}' ~/.startos/config.yaml); \
if [ -z "$$HOST" ]; then \
echo "Error: You must define \"host: http://server-name.local\" in ~/.startos/config.yaml"; \
exit 1; \
fi; \
S9PK=$$(ls -t *.s9pk 2>/dev/null | head -1); \
if [ -z "$$S9PK" ]; then \
echo "Error: No .s9pk file found. Run 'make' first."; \
exit 1; \
fi; \
printf "\n🚀 Installing %s to %s ...\n" "$$S9PK" "$$HOST"; \
start-cli package install -s "$$S9PK"
publish: | all
@REGISTRY=$$(awk -F'/' '/^registry:/ {print $$3}' ~/.startos/config.yaml); \
if [ -z "$$REGISTRY" ]; then \
echo "Error: You must define \"registry: https://my-registry.tld\" in ~/.startos/config.yaml"; \
exit 1; \
fi; \
S3BASE=$$(awk -F'/' '/^s9pk-s3base:/ {print $$3}' ~/.startos/config.yaml); \
if [ -z "$$S3BASE" ]; then \
echo "Error: You must define \"s3base: https://s9pks.my-s3-bucket.tld\" in ~/.startos/config.yaml"; \
exit 1; \
fi; \
command -v s3cmd >/dev/null || \
(echo "Error: s3cmd not found. It must be installed to publish using s3." && exit 1); \
printf "\n🚀 Publishing to %s; indexing on %s ...\n" "$$S3BASE" "$$REGISTRY"; \
for s9pk in *.s9pk; do \
age=$$(( $$(date +%s) - $$(stat -c %Y "$$s9pk") )); \
if [ "$$age" -gt 3600 ]; then \
printf "\033[1;33m⚠️ %s is %d minutes old. Publish anyway? [y/N] \033[0m" "$$s9pk" "$$((age / 60))"; \
read -r ans; \
case "$$ans" in [yY]*) ;; *) echo "Skipping $$s9pk"; continue ;; esac; \
fi; \
start-cli s9pk publish "$$s9pk"; \
done
check-deps:
@command -v start-cli >/dev/null || \
(echo "Error: start-cli not found. Please see https://docs.start9.com/latest/developer-guide/sdk/installing-the-sdk" && exit 1)
@command -v npm >/dev/null || \
(echo "Error: npm not found. Please install Node.js and npm." && exit 1)
check-init:
@if [ ! -f ~/.startos/developer.key.pem ]; then \
echo "Initializing StartOS developer environment..."; \
start-cli init-key; \
fi
javascript/index.js: $(shell find startos -type f) tsconfig.json node_modules
npm run check
npm run build
node_modules: package-lock.json
npm ci
package-lock.json: package.json
npm i
clean:
@echo "Cleaning up build artifacts..."
@rm -rf $(PACKAGE_ID).s9pk $(PACKAGE_ID)_x86_64.s9pk $(PACKAGE_ID)_aarch64.s9pk $(PACKAGE_ID)_riscv64.s9pk javascript node_modules
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+19 -1
View File
@@ -4,6 +4,7 @@ import { sdk } from '../sdk'
import {
DEFAULT_COINGECKO_TOKEN_COINS,
DEFAULT_OPERATOR_RELAY,
DEFAULT_PLATFORM_CALLBACK_HOST,
DEFAULT_PLATFORM_MODE,
} from '../utils'
@@ -103,6 +104,20 @@ const inputSpec = InputSpec.of({
minLength: null,
maxLength: null,
}),
platformCallbackHost: Value.text({
name: i18n('CALLBACK HOST'),
description: i18n(
'Callback hostname SpacesOps uses for cert-callback flows (PLATFORM_CALLBACK_HOST). Leave blank to use spacesops.startos.',
),
warning: null,
footnote: null,
default: DEFAULT_PLATFORM_CALLBACK_HOST,
required: false,
masked: false,
placeholder: 'spacesops.startos',
minLength: null,
maxLength: null,
}),
})
export const configurePlatform = sdk.Action.withInput(
@@ -113,7 +128,7 @@ export const configurePlatform = sdk.Action.withInput(
async ({ effects }) => ({
name: i18n('Configure Platform'),
description: i18n(
'Set optional SpacesOps settings: Nostr relay, theme mode, CoinGecko pricing, and SUBS backend. Saving restarts the service so the new settings take effect.',
'Set optional SpacesOps settings: Nostr relay, theme mode, CoinGecko pricing, SUBS backend, and callback host. Saving restarts the service so the new settings take effect.',
),
warning: null,
allowedStatuses: 'any',
@@ -136,6 +151,8 @@ export const configurePlatform = sdk.Action.withInput(
subsUrl: store?.subsUrl ?? null,
subsUser: store?.subsUser ?? null,
subsPassword: store?.subsPassword ?? null,
platformCallbackHost:
store?.platformCallbackHost ?? DEFAULT_PLATFORM_CALLBACK_HOST,
}
},
@@ -149,6 +166,7 @@ export const configurePlatform = sdk.Action.withInput(
subsUrl: input.subsUrl || null,
subsUser: input.subsUser || null,
subsPassword: input.subsPassword || null,
platformCallbackHost: input.platformCallbackHost?.trim() || null,
})
return {
+1
View File
@@ -16,6 +16,7 @@ const shape = z.object({
subsUrl: z.string().nullable().catch(null),
subsUser: z.string().nullable().catch(null),
subsPassword: z.string().nullable().catch(null),
platformCallbackHost: z.string().nullable().catch(null),
})
export const storeJson = FileHelper.json(
+3 -1
View File
@@ -16,7 +16,7 @@ const dict = {
'SUBS RPC Password': 12,
'Optional SUBS RPC password (SUBS_RPC_PASSWORD).': 13,
'Configure Platform': 14,
'Set optional SpacesOps settings: Nostr relay, theme mode, CoinGecko pricing, and SUBS backend. Saving restarts the service so the new settings take effect.': 15,
'Set optional SpacesOps settings: Nostr relay, theme mode, CoinGecko pricing, SUBS backend, and callback host. Saving restarts the service so the new settings take effect.': 15,
Success: 16,
'Platform configuration saved. The service is restarting to apply the new settings.': 17,
'Operator Secret Key (hex)': 18,
@@ -50,6 +50,8 @@ const dict = {
'Web Interface': 46,
'The web interface is ready': 47,
'The web interface is not ready': 48,
'CALLBACK HOST': 49,
'Callback hostname SpacesOps uses for cert-callback flows (PLATFORM_CALLBACK_HOST). Leave blank to use spacesops.startos.': 50,
} as const
/**
+9 -6
View File
@@ -5,6 +5,7 @@ import { sdk } from './sdk'
import {
dataDir,
DEFAULT_OPERATOR_RELAY,
DEFAULT_PLATFORM_CALLBACK_HOST,
DEFAULT_PLATFORM_MODE,
SPACED_RPC_URL,
SPACED_WALLETLOAD_NAME,
@@ -54,7 +55,7 @@ export const main = sdk.setupMain(async ({ effects }) => {
type: 'directory',
})
const sub = await sdk.SubContainer.of(
const sub = sdk.SubContainer.of(
effects,
{ imageId: 'spacesops' },
mounts,
@@ -110,12 +111,14 @@ export const main = sdk.setupMain(async ({ effects }) => {
if (store.subsUrl) env.SUBS_URI_VALUE = store.subsUrl
if (store.subsUser) env.SUBS_RPC_USER = store.subsUser
if (store.subsPassword) env.SUBS_RPC_PASSWORD = store.subsPassword
env.PLATFORM_CALLBACK_HOST =
store.platformCallbackHost ?? DEFAULT_PLATFORM_CALLBACK_HOST
// v1.0.1's entrypoint sources setup-spacesops-env.sh with set -u. That file
// exports NODE_EXTRA_CA_CERTS using ${_SCRIPT_DIR}, but _SCRIPT_DIR is set on
// a separate non-export line the entrypoint never evals — startup crashes
// unless NODE_EXTRA_CA_CERTS is already set. Fetch the StartOS root CA for
// outbound *.startos HTTPS (SUBS_URI host when configured, else Spaces).
// The image's setup-spacesops-env.sh defaults NODE_EXTRA_CA_CERTS to
// /app/certs/startos-local-root-ca.pem, a root CA baked in at build time from
// another box. Fetch this box's StartOS root CA and point the variable at it
// instead, so outbound HTTPS to *.startos succeeds (SUBS_URI host when
// configured, else Spaces).
const caHostname =
(store.subsUrl && startOsHostnameFromUrl(store.subsUrl)) ||
`${SPACES_PACKAGE_ID}.startos`
+1 -13
View File
@@ -9,26 +9,14 @@ export const manifest = setupManifest({
upstreamRepo: 'https://git.spacesops.com/spacesops/spacesops',
marketingUrl: 'https://spacesops.com',
donationUrl: null,
docsUrls: [],
description: { short, long },
volumes: ['main'],
images: {
spacesops: {
source: { dockerTag: 'spacesops/spacesops:v1.0.1' },
source: { dockerTag: 'spacesops/spacesops:v1.0.4' },
arch: ['x86_64', 'aarch64'],
},
},
alerts: {
install: {
en_US:
'SpacesOps REQUIRES the Spaces service. Install and sync Spaces first — SpacesOps auto-connects to it at spaces.startos:7225 by reading the Spaces RPC credentials, and will not start until they are available.\n\nWARNING: the admin area is protected by a FIXED, well-known credential baked into this image (username "admin", password "Whatever!") that cannot be changed without rebuilding the image. The admin area can run SQL and manage tenants. Keep this service private (Tor-only) and do NOT expose its admin routes to the public internet. See the "Show Admin Credentials" action.',
},
update: null,
uninstall: null,
restore: null,
start: null,
stop: null,
},
dependencies: {
spaces: {
description: depSpacesDescription,
+12 -8
View File
@@ -18,18 +18,19 @@ export const SPACES_PACKAGE_ID = 'spaces'
// Spaces exposes its spaced JSON-RPC as the `spaces-api` interface on 7225,
// reachable from a dependent package at this address.
export const SPACED_RPC_URL = 'http://spaces.startos:7225'
export const SPACED_WALLETLOAD_NAME = 'main'
export const SPACED_WALLETLOAD_NAME = 'default'
// Admin Basic Auth is baked into the v1.0.1 image with NO env override. It
// cannot be changed without rebuilding the image. Surfaced (with a warning)
// via the "Show Admin Credentials" action.
// The app's admin Basic Auth defaults, which it uses when
// PLATFORM_ADMIN_USERNAME / PLATFORM_ADMIN_PASSWORD are unset. This package
// does not currently set either, so these well-known values are live —
// surfaced (with a warning) via the "Show Admin Credentials" action.
export const ADMIN_USER = 'admin'
export const ADMIN_PASSWORD = 'Whatever!'
// Where StartOS writes the StartOS root CA for outbound *.startos HTTPS (see
// main.ts). Always injected as NODE_EXTRA_CA_CERTS — required on v1.0.1+ where
// the image entrypoint's setup-spacesops-env.sh references _SCRIPT_DIR without
// defining it under set -u.
// Where StartOS writes this box's StartOS root CA for outbound *.startos HTTPS
// (see main.ts). Always injected as NODE_EXTRA_CA_CERTS, which overrides the
// image's own default of /app/certs/startos-local-root-ca.pem — a CA baked in
// at build time that does not match this box.
export const nodeExtraCaCertVolumeSubpath = '.startos/startos-root-ca.crt'
export const nodeExtraCaCertContainerPath = `${dataDir}/.startos/startos-root-ca.crt`
@@ -51,6 +52,9 @@ export function startOsHostnameFromUrl(url: string): string | null {
export const DEFAULT_OPERATOR_RELAY = 'wss://relay.primal.net'
export const DEFAULT_PLATFORM_MODE = 'prod'
export const DEFAULT_COINGECKO_TOKEN_COINS = 'bitcoin'
// Hostname SpacesOps uses when building payment callback URLs
// (http://${PLATFORM_CALLBACK_HOST}:${PORT}/...).
export const DEFAULT_PLATFORM_CALLBACK_HOST = 'spacesops.startos'
// 32 random bytes as a 64-char hex string — a secp256k1/Nostr secret key. The
// odds of an out-of-range key are ~1 in 2^128; if getPublicKey rejects it,
+18
View File
@@ -0,0 +1,18 @@
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
export const current = VersionInfo.of({
version: '1.0.4:0',
releaseNotes: {
en_US: `Updates SpacesOps to v1.0.4 and rebuilds the package on the current StartOS packaging SDK.
- Upstream image is spacesops/spacesops:v1.0.4 on x86_64 and aarch64. The application itself is updated; the container entrypoint and Node runtime are unchanged from v1.0.3.
- Rebuilt against start-sdk 2.x, so this release requires StartOS 0.4.0-beta.10 or later.
- The install-time warning about the fixed admin credentials now lives in the service instructions, since StartOS no longer shows install alerts.
Your operator keypair, session secret, and Configure Platform settings are preserved.`,
},
migrations: {
up: async ({ effects }) => {},
down: IMPOSSIBLE,
},
})
+3 -4
View File
@@ -1,8 +1,7 @@
import { VersionGraph } from '@start9labs/start-sdk'
import { v_1_0_1_0 } from './v1.0.1.0'
import { v_1_0_1_1 } from './v1.0.1.1'
import { current } from './current'
export const versionGraph = VersionGraph.of({
current: v_1_0_1_1,
other: [v_1_0_1_0],
current,
other: [],
})
-14
View File
@@ -1,14 +0,0 @@
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
export const v_1_0_1_0 = VersionInfo.of({
version: '1.0.1:0',
releaseNotes: {
en_US: `Upstream upgrade to SpacesOps v1.0.1.
- Bumps the image to spacesops/spacesops:v1.0.1 on x86_64 and aarch64.
- No StartOS-side configuration, action, or migration changes; existing operator keypair, session secret, and Configure-Platform settings are preserved.`,
},
migrations: {
up: async ({ effects }) => {},
down: IMPOSSIBLE,
},
})
-13
View File
@@ -1,13 +0,0 @@
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
export const v_1_0_1_1 = VersionInfo.of({
version: '1.0.1:1',
releaseNotes: {
en_US: `- Always sets NODE_EXTRA_CA_CERTS before the v1.0.1 image entrypoint runs, fetching the StartOS root CA via sdk.getSslCertificate (SUBS *.startos hostname when configured, otherwise spaces.startos). Fixes startup crash where setup-spacesops-env.sh references unset _SCRIPT_DIR under set -u.
- Enables outbound HTTPS to same-host StartOS services from SpacesOps.`,
},
migrations: {
up: async ({ effects }) => {},
down: IMPOSSIBLE,
},
})
+2 -9
View File
@@ -1,11 +1,4 @@
{
"include": ["startos/**/*.ts", "node_modules/**/startos"],
"compilerOptions": {
"target": "ES2018",
"module": "CommonJS",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true
}
"extends": "@start9labs/start-sdk/tsconfig.base.json",
"include": ["startos/**/*.ts", "node_modules/**/startos"]
}