Skip to main content

Scripticus server

The index service for Scripticus, a package manager and registry for scripts. The server provides manifest-aware search, version listing, and the atomic publish path for a Scripticus registry. Installing this package provides the scripticus-svr command.

Running the server

The recommended way to run a Scripticus registry is the Docker Compose bundle: a reverse proxy fronting the index service and the Gitea instance that provides storage, authentication, and namespace ownership. Server releases publish a Docker image to kevinchannon/scripticus-server (tagged with the release version and latest), and the repository's docker-compose.yml wires the whole bundle together — no checkout needed. The proxy is the single URL clients use (http://localhost:8000): it routes blob downloads to Gitea and everything else to the index, so a client needs no Gitea address of its own (D45). The bundle publishes exactly one port: account management is served through the same front at http://localhost:8000/accounts (D62), so there is no second port to open.

The get-scripticus-svr script does the whole standup (D61) — it checks the host, fetches the compose bundle, starts it, and creates your Gitea admin account with a correctly-scoped publish token:

$ curl -fsSL https://raw.githubusercontent.com/kevinchannon/scripticus/main/get-scripticus-svr | sh

It asks three things — where to put the stack, the administrator's account name, and the organisation to publish under — then prints a username, password, and token. Save all three then — Gitea shows a token once, and the script will not mint a second one for an account that already exists.

The administrator and the publishing namespace are deliberately separate. A namespace is a Gitea user or organisation, so the person running the registry does not have to be the identity packages belong to: answer acme-co to the namespace question and packages read acme-co/backup-rotate, while the admin account stays a person. Skipping it publishes under the admin's own username, which is fine for a personal registry and a trap for a shared one — every reference already published keeps that name.

Options go after -s --, since a pipe leaves nowhere else to put them:

$ curl -fsSL .../get-scripticus-svr | sh -s -- --dir /srv/registry --port 9000

--dir, --user, --org, --email, and --port cover the non-interactive case; --help lists them. Pass --public-url if the registry will not be reached at http://localhost:<port> — the account pages build their links from it, so getting it wrong leaves a working registry with broken links.

If you would rather read it before running it — a fair instinct for anything piped into a shell — download it first and run it separately; the script behaves identically either way:

$ curl -fsSLO https://raw.githubusercontent.com/kevinchannon/scripticus/main/get-scripticus-svr
$ less get-scripticus-svr
$ sh get-scripticus-svr

It refuses rather than repairs: an existing directory, compose stack, or Gitea user stops the run rather than modifying what is already there. It needs Docker, the Compose v2 plugin at v2.23.1 or newer (the bundle carries its proxy config inline), and either curl or wget.

Running the index service directly

Of course, you can also just run the index service on its own — without the proxy-and-Gitea bundle — which is handy for development or slotting it into infrastructure you already operate. scripticus-svr starts the service, printing its version and address on start-up:

$ scripticus-svr --host 0.0.0.0 --port 8000
scripticus-svr 0.1.0 — serving on http://0.0.0.0:8000 (interactive API docs at http://0.0.0.0:8000/docs)

Both options are optional; the default is 127.0.0.1:8000. The API is self-describing: interactive docs are served at /docs and the OpenAPI spec at /openapi.json.

Run this way, the index service still needs a Gitea instance to publish against (SCRIPTICUS_GITEA_URL, default http://localhost:3000) and an index database — a local SQLite file (scripticus-index.db) by default, or set SCRIPTICUS_INDEX_DB to any SQLAlchemy URL to point elsewhere; tables are created automatically on first use. The Compose bundle provides both for you.

Health check

GET /health returns 200 with {"status": "ok"} while the service is up. It is deliberately unauthenticated — it's a liveness probe for load balancers and container orchestrators.

Version

GET /version returns the running server's version, e.g. {"version": "0.1.1"}.

Package index (read API)

  • GET /packages/{namespace}/{name} — a package's version listing, newest first by semver precedence. Yanked versions are included and marked ("yanked": true) so pinned lookups can still see them; unknown packages return 404.
  • GET /search?q=<substring>&platform=<os>&language=<lang> — packages whose name contains q (all parameters optional), with each result's latest non-yanked version. Yanked versions are invisible to search; platform and language filter on the artifacts a version actually provides.

Publishing

POST /packages publishes a package version: a multipart upload of one or more archives — a version's whole format-group set, as produced by scripticus pack, one repeated archives part each — with your Gitea token in the Authorization header. This is what scripticus publish does for you; the raw request looks like:

$ curl -X POST http://localhost:8000/packages \
    -H "Authorization: token <your-gitea-token>" \
    -F archives=@my_tool-1.0.0-linux.macos-bash.tar.gz \
    -F archives=@my_tool-1.0.0-windows-bash.zip

The server trusts nothing about the upload: it re-validates every archive's manifest and package tree, checks the batch is one content tree in different archive formats, computes the content hash, checks with Gitea (live) that your token may publish to the manifest's namespace — your own username, or an organisation you belong to — stores the blobs in Gitea's generic package registry, and only then commits the index record. The batch is atomic: if any archive fails validation or any write fails, nothing is published. Versions are immutable; the one addition an existing version accepts is an artifact in a new archive format carrying the identical content hash. Declared package dependencies must be fully namespaced and already present in the index, and a publish that would create a dependency cycle is rejected. The library namespace is reserved. The Gitea instance is configured with SCRIPTICUS_GITEA_URL (default http://localhost:3000).

Yanking

PATCH /packages/{namespace}/{name}/{version} with a JSON body of {"yanked": true} hides a published version from search and latest/range resolution while leaving it fetchable by anything that pins it exactly — no hard delete. {"yanked": false} reverses it. Auth is the same live, namespace-scoped Gitea check as publishing, so only a namespace owner can yank. This is what scripticus yank (and yank --undo) does for you:

$ curl -X PATCH http://localhost:8000/packages/infra/backup-rotate/1.2.0 \
    -H "Authorization: token <your-gitea-token>" \
    -H "Content-Type: application/json" \
    -d '{"yanked": true}'

Unlike publish, this touches no Gitea blob — it flips one flag on the index record. An unknown version is a 404; yank is idempotent and carries no time window, so a version can be un-yanked at any time.

Licence

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

scripticus_server-0.8.0.tar.gz (21.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

scripticus_server-0.8.0-py3-none-any.whl (25.4 kB view details)

Uploaded Python 3

File details

Details for the file scripticus_server-0.8.0.tar.gz.

File metadata

  • Download URL: scripticus_server-0.8.0.tar.gz
  • Upload date:
  • Size: 21.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for scripticus_server-0.8.0.tar.gz
Algorithm Hash digest
SHA256 cc3bcaf8a1717a884018dfc7e178383f4783a2ed3cde4ce13e8829be58ba8645
MD5 06a376add5c3fcc482e6f1cdbf1688b3
BLAKE2b-256 e30ead68342c70dc34981caab7d7b682bd50554d4a0f671aa71e6291817b11a1

See more details on using hashes here.

Provenance

The following attestation bundles were made for scripticus_server-0.8.0.tar.gz:

Publisher: release.yml on kevinchannon/scripticus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file scripticus_server-0.8.0-py3-none-any.whl.

File metadata

File hashes

Hashes for scripticus_server-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 80c03da4dda6357cb5e6903a9c792b074a410039159102321e3bc5c754dcaa76
MD5 539c5ec221ddbe702e7e583529202660
BLAKE2b-256 32d18ac6e95bf487e1f204e953ffbc94210257ec14ed60a83acf35a1a565a752

See more details on using hashes here.

Provenance

The following attestation bundles were made for scripticus_server-0.8.0-py3-none-any.whl:

Publisher: release.yml on kevinchannon/scripticus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page