2024-12-12 00:42:41 +01:00
2024-12-12 00:42:41 +01:00
2026-08-12 12:45:20 +00:00
2024-12-12 00:42:41 +01:00
2024-12-12 00:42:41 +01:00
2024-12-12 00:42:41 +01:00
2024-12-12 00:42:41 +01:00
2024-12-12 00:42:41 +01:00

foss.global

Official codebase for the foss.global website, built with TypeScript and the @api.global ecosystem.

Issue Reporting and Security

For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.

Prerequisites

  • Node.js (>=20)
  • pnpm 11
  • Git CLI when the optional Git hosting runtime is enabled
  • MongoDB connection for SmartData-backed public snapshots
  • MONGODB_URL/MONGODB_URI/MONGO_URL for the MongoDB connection URL
  • Optional MONGODB_DATABASE/MONGODB_DB/MONGO_DB override; defaults to foss_global

Installation

pnpm install

Build

Compile TypeScript and bundle the website:

pnpm build

Watch

Rebuild on file changes:

pnpm watch

Start

Start the CLI web server:

pnpm start

Start using the TypeScript entrypoint:

pnpm run startTs

Usage Example

After starting the server, open your browser at http://localhost:3000 to view the site and API.

Optional Git Hosting Runtime

The Git runtime is disabled by default. When explicitly enabled, the same backend process serves:

  • the website on port 3000;
  • the CI V1 control plane on port 3001 when CI V1 is enabled;
  • the isolated CI V2 control plane on its configured port when CI V2 is enabled;
  • Git Smart HTTP and its administration API on port 3002;
  • authenticated Git SSH on internal port 29419 when SSH is enabled, advertised externally on port 29460.

CI V2 and Git Smart HTTP both default to port 3002, so configure a distinct CI_V2_CONTROL_PLANE_PORT before enabling them together.

Repository metadata, visibility, and native bundle descriptors are authoritative in SmartData. On startup, the runtime imports desired-public mirrors and restores every native repository from its SHA-256-addressed SmartBucket bundle. Authorized private mirrors hydrate on first access. Native repositories without a bundle are initialized as empty bare repositories. Partial metadata, a missing storage configuration, an unexpected object key, a size mismatch, or a digest mismatch fails startup closed. Live publication and revocation must use GitHostingRuntime.setRepositoryVisibility() so hydration, Smart HTTP access, public reads, and Codefeed change together; raw database visibility writes are unsupported.

Quota reconstruction accepts exactly 10,000 release repositories or package owners and rejects grouped or merged identity overflow before writes. Stored quota scans fail closed above 100,000 rows. Computed quotas are upserted before stale rows are removed with exact value fences, including stale nonzero rows, so reconstruction does not expose a temporary unmetered window.

Scheduled maintenance serializes with repository mutations, runs git fsck, restores current bundles into isolated disposable GitManager instances, compares every ref, reconciles reachable Git LFS pointers, and only then advances retention garbage collection. Bundle history, LFS objects, CI source archives, and CI caches are quota-accounted in SmartData; immutable shared objects use reference-aware mark/sweep collection with crash-recoverable deletion leases.

Mirror checkouts and restored repositories live only in a disposable process-local directory. Mirrors rebuild from their configured upstream URLs. Native repository durability comes only from SmartBucket objects plus SmartData descriptors. Smart HTTP and SSH pushes share one per-repository mutation lock, the same role authorization and immutable protected-ref policy, and the same durable snapshot, CI event, and audit path. The final receive-pack status is withheld until persistence succeeds. A snapshot failure stops the ingress and terminates the runtime so a supervisor restart restores the last durable state.

When native Git writes and CI are both enabled, each repository dispatch is pinned to the pushed commit's exact object ID. GitManager creates a bounded deterministic tar.gz source archive, the backend verifies its SHA-256 digest and stores it under a content-addressed SmartBucket key, and that immutable descriptor is persisted with the pending job before enqueueing it. Only the runner holding the job's current unexpired lease can download the archive. The runner authenticates only to the exact same-origin source endpoint and verifies the digest before extraction.

Configuration:

Variable Default Purpose
GIT_SMART_HTTP_ENABLED false Explicitly enables the runtime.
GIT_SMART_HTTP_HOST 127.0.0.1 Public service listener address behind the platform TLS route.
GIT_SMART_HTTP_PORT 3002 Git service port; it must not collide with the website or CI listener.
GIT_SMART_HTTP_ALLOW_NON_LOOPBACK false Required with a non-loopback bind after protected TLS ingress exists.
GIT_SMART_HTTP_PUBLIC_BASE_URL required when enabled External HTTPS clone origin, for example https://code.foss.global.
GIT_PUBLIC_BASE_URL https://foss.global External repository-page origin.
GIT_SSH_PUBLIC_BASE_URL ssh://git@code.foss.global:29460 Advertised SSH clone origin.
GIT_SSH_ENABLED false Enables the public-key-only SSH Git listener; Smart HTTP must also be enabled.
GIT_SSH_HOST 127.0.0.1 SSH listener address. Use a non-loopback address only with the explicit override.
GIT_SSH_PORT 29419 Raw SSH listener port; it must not collide with the website, CI, or Smart HTTP listener.
GIT_SSH_ALLOW_NON_LOOPBACK false Required with a non-loopback SSH bind.
GIT_SSH_HOST_KEY none Required OpenSSH/PEM private host key. Treat it as a deployment secret and keep it stable across restarts.
GIT_SSH_MAX_CONNECTIONS 256 Maximum concurrent SSH connections.
GIT_SSH_MAX_SESSIONS 128 Maximum concurrent SSH sessions across all connections.
GIT_MIRROR_MAX_REPOSITORIES 250 Startup hydration limit.
GIT_WRITE_ENABLED false Enables native repository administration and receive-pack.
GIT_ADMIN_TOKEN none Required 32512 character bearer token when writes are enabled.
GIT_MAX_PUSH_BYTES 4294967296 Maximum streamed receive-pack request size.
GIT_WEBHOOK_ENCRYPTION_KEY none Optional 64-character hexadecimal AES-256 key that enables encrypted repository webhook secrets; writes must be enabled, and the key must remain stable across restarts.
GIT_WEBHOOK_ALLOWED_HOSTS none Required comma-separated exact DNS hostname allowlist when webhooks are enabled. Destinations must use HTTPS on port 443 and resolve only to public addresses.
GIT_WEBHOOK_MAXIMUM_ATTEMPTS 8 Maximum signed delivery attempts before a webhook delivery is marked failed.
GIT_STORAGE_ENDPOINT none S3-compatible hostname without credentials, a port, or a path; required when native repositories exist.
GIT_STORAGE_PORT 443 with SSL, otherwise 80 S3-compatible object-store port.
GIT_STORAGE_USE_SSL true Selects HTTPS and must match an endpoint URL scheme when one is supplied.
GIT_STORAGE_REGION us-east-1 Object-store region.
GIT_STORAGE_ACCESS_KEY none Required object-store access key.
GIT_STORAGE_ACCESS_SECRET none Required object-store secret.
GIT_STORAGE_BUCKET none Required S3 bucket for repository bundles and CI source archives; it is created when absent.
GIT_STORAGE_MAX_BUNDLE_BYTES 8589934592 Maximum bundle size accepted by GitManager and the storage verifier.
GIT_STORAGE_MAX_BUNDLE_REPOSITORY_BYTES 68719476736 Maximum retained current and historical bundle bytes per repository; capacity pressure evicts the oldest non-current bundle.
GIT_STORAGE_BUNDLE_RETENTION_DAYS 30 Minimum age before a non-current repository bundle becomes eligible for deletion.
GIT_STORAGE_MAX_ARCHIVE_BYTES 134217728 Maximum source archive file size accepted by GitManager and the storage verifier.
GIT_STORAGE_MAX_SOURCE_REPOSITORY_BYTES 21474836480 Maximum retained CI source archive bytes per repository.
GIT_STORAGE_SOURCE_RETENTION_DAYS 30 Minimum inactivity window before an unreferenced CI source archive becomes eligible for deletion.
GIT_STORAGE_MAX_LFS_OBJECT_BYTES 5368709120 Maximum size of one verified Git LFS object.
GIT_STORAGE_MAX_LFS_REPOSITORY_BYTES 107374182400 Maximum total reserved and retained Git LFS bytes per repository.
GIT_STORAGE_MAX_RELEASE_ASSET_BYTES 2147483648 Maximum size of one streamed release asset.
GIT_STORAGE_MAX_RELEASE_REPOSITORY_BYTES 53687091200 Maximum total reserved and retained release-asset bytes per repository.
GIT_STORAGE_MAX_NPM_PACKAGE_BYTES 134217728 Maximum decoded tarball size of one npm package version.
GIT_STORAGE_MAX_NPM_OWNER_BYTES 107374182400 Maximum total reserved and retained npm package bytes per organization owner.
GIT_STORAGE_MAX_GENERIC_PACKAGE_FILE_BYTES 2147483648 Maximum size of one streamed generic package file.
GIT_STORAGE_MAX_GENERIC_PACKAGE_OWNER_BYTES 107374182400 Maximum total reserved and retained generic package bytes per organization owner.
GIT_STORAGE_MAX_OCI_BLOB_BYTES 21474836480 Maximum size of one OCI image layer or configuration blob.
GIT_STORAGE_MAX_OCI_MANIFEST_BYTES 8388608 Maximum size of one exact OCI manifest or index.
GIT_STORAGE_MAX_OCI_OWNER_BYTES 536870912000 Maximum total reserved and retained OCI blob and manifest bytes per organization owner.
GIT_STORAGE_LFS_RETENTION_DAYS 30 Minimum age before repository LFS metadata unreachable from every ref becomes eligible for deletion.
GIT_STORAGE_OBJECT_GC_GRACE_HOURS 24 Mark/sweep grace period for unreferenced shared LFS objects.
GIT_STORAGE_MAINTENANCE_INTERVAL_MINUTES 60 Interval for bounded LFS reachability reconciliation and retention collection.
GIT_STORAGE_INTEGRITY_CHECK_INTERVAL_HOURS 24 Interval for full repository fsck and isolated bundle restore drills.
CI_CACHE_OBJECT_GC_GRACE_HOURS 24 Mark/sweep grace period for immutable CI cache objects no longer referenced by cache metadata or active uploads.
CI_V2_ADMIN_TOKEN required 328192 character bearer token for the isolated V2 administration routes.
CI_V2_BOOTSTRAP_TOKEN required One-time runner bootstrap bearer token; durable state stores only its keyed digest.
CI_V2_BOOTSTRAP_TRUST_CLASS required Trust class assigned to the bootstrapped runner and matched when jobs are claimed.
CI_V2_BOOTSTRAP_ALLOWED_LABELS none Comma-separated runner-label allowlist, with at most 32 unique protocol identifiers.
CI_V2_CREDENTIAL_DIGEST_KEY required 64-character hexadecimal root key for bootstrap/runner credential HMACs and an HKDF-separated enqueue-idempotency HMAC. Rotating it invalidates existing runner credentials and makes retained enqueue replays conflict.
CI_V2_REPLAY_KEY_ID required Persisted identifier for the current replay AES-256-GCM key.
CI_V2_REPLAY_KEY required Current 64-character hexadecimal replay encryption key.
CI_V2_PREVIOUS_REPLAY_KEY_ID none Previous replay key identifier; configure it together with the previous key while retained records reference it.
CI_V2_PREVIOUS_REPLAY_KEY none Previous 64-character hexadecimal replay encryption key.
CI_V2_JOB_SECRET_KEY_ID required Persisted identifier for the current job-secret AES-256-GCM key.
CI_V2_JOB_SECRET_KEY required Current 64-character hexadecimal job-secret encryption key.
CI_V2_PREVIOUS_JOB_SECRET_KEY_ID none Previous job-secret key identifier; configure it together with the previous key while active jobs reference it.
CI_V2_PREVIOUS_JOB_SECRET_KEY none Previous 64-character hexadecimal job-secret encryption key.
CI_V2_CACHE_VALIDATION_EPOCH required Durable cache-validation policy identifier; a configured/durable mismatch fails startup.
CI_V2_CONTROL_PLANE_HOST 127.0.0.1 Isolated V2 listener address.
CI_V2_CONTROL_PLANE_PORT 3002 Isolated V2 listener port; it must not collide with the website, CI V1, Git, or SSH listeners.
CI_V2_CONTROL_PLANE_ALLOW_NON_LOOPBACK false Required with a non-loopback V2 bind after protected TLS ingress exists; enabling it also requires CI_V2_CONTROL_PLANE_PUBLIC_BASE_URL.
CI_V2_CONTROL_PLANE_PUBLIC_BASE_URL none Credential-free HTTPS origin required for every non-loopback V2 bind and routed directly to the V2 listener; paths are rooted at /api/runner/v2 and /api/ci/v2.
CI_V2_SOURCE_RETENTION_DAYS 14 Minimum inactivity window before an unreferenced V2 source archive is eligible for deletion.
CI_V2_MAXIMUM_SOURCE_REPOSITORY_BYTES 21474836480 Maximum retained V2 source archive bytes per repository.

On Cloudly, the canonical object-storage binding variables (S3_ENDPOINT_HOST, S3_ENDPOINT, S3_PORT, S3_USE_SSL, S3_REGION, access-key aliases, secret-key aliases, and S3_BUCKET) provide the storage values automatically. Explicit GIT_STORAGE_* values take precedence.

The CI control plane is enabled when any CI variable is configured. CI_RUNNER_SIGNING_SECRET, CI_JOB_ENCRYPTION_KEY, and CI_ADMIN_TOKEN are then required. CI_CONTROL_PLANE_PUBLIC_BASE_URL is additionally required when Git writes are enabled so jobs receive an externally reachable source URL. It must be the credential-free HTTPS origin routed to port 3001; runner credentials are never embedded in job specifications.

CI V2 remains absent only while every mapped CI_V2_* variable is unset or empty. Any non-empty V2 value enters strict configuration validation, and all values marked required above must then be present. It implements foss-ci-runner/2.0-draft.2 on a separate socket and uses only ffb_ci_v2_* SmartData collections and ci/v2/sources/ object keys. Enabling it also requires GIT_SMART_HTTP_ENABLED=true and complete GIT_STORAGE_* configuration. It does not move repository triggers away from CI V1.

The V2 runner surface provides discovery at GET /api/runner/v2, registration at POST /api/runner/v2/runners/register, session creation and heartbeat under /api/runner/v2/runners/:runnerId, claiming at POST /api/runner/v2/jobs/claim, attempt accept, heartbeat, log, completion, and abandonment under /api/runner/v2/jobs/:jobId/attempts/:attemptId, recovery at POST /api/runner/v2/jobs/recover, and source download at GET /api/runner/v2/sources/:sha256. Artifact and cache transfer paths are present only to fail closed during the initial source-only activation.

The V2 admin surface provides readiness at GET /api/ci/v2/readiness, source preparation at POST /api/ci/v2/sources, enqueue at POST /api/ci/v2/jobs, job status and cancellation under /api/ci/v2/jobs/:jobId, bounded log reads at GET /api/ci/v2/jobs/:jobId/logs, and runner drain control at POST /api/ci/v2/runners/:runnerId/drain. Initial admission is restricted to admin-prepared, admin-enqueued source-only jobs. Artifact and cache declarations are rejected. Source archives are bounded to 8 GiB compressed, 64 GiB extracted regular-file data, 1,000,000 entries, and 134,217,728 bytes of path metadata. Source preparation accepts only active, non-archived native repositories.

Bootstrap and runner tokens are stored only as keyed HMAC-SHA256 digests. Replay payloads and pending credential replacements use one AES-256-GCM key set; job secrets use a separate key set. Keep previous keys configured while readiness reports retained references to them. Changing CI_V2_CACHE_VALIDATION_EPOCH requires an explicit data migration rather than an environment-only change. Terminal jobs, attempts, logs, released source references, invalidated sessions, and audit records are retained for 30 days and then removed by bounded background cleanup. Enqueue idempotency keys are unique within a tenant, so independent tenants may safely use the same key. Readiness fails closed when the control-plane lifecycle, database, reaper timer, reaper freshness, retained replay keys, or active job-secret keys are unhealthy.

CI V2 JSON requests and responses are limited to 2 MiB. One UTF-8 log chunk is limited to 64 KiB and one attempt to 1 GiB, with lower limits applied when negotiated by the job. Admin log reads require attemptId, default fromSequence to zero, and return at most five chunks. Oversized request bodies, log writes, and JSON responses fail with HTTP 413.

Claim selection scans queued jobs in deterministic order, fails closed above 100,000 examined jobs or a 30-second deadline, and serializes claim admission with runner drain updates. After cancellation is accepted, completion must use status canceled and the exact cancellation request ID; cancellation deadlines fence acceptance, heartbeat, new logs, completion, and new source-download admission. Concurrent process-exit paths share one shutdown operation and wait for the same dependency cleanup. Request disconnects cancel source preparation and downloads; shutdown cancels and drains lifecycle-owned source preparation, downloads, and reaping before dependencies close. These paths propagate cancellation through @foss.global/gitmanager 1.7.0 and @push.rocks/smartbucket 4.13.0 object existence, removal, upload, verification, and download operations. Once the atomic source ready transition succeeds, publication wins over a later cancellation and the prepared source remains available.

These cancellation contracts do not activate CI V2. Activation still requires durable cross-replica runner-session and credential revocation, or an enforceable single-replica invariant, in addition to the Git Smart HTTP and storage prerequisites above.

CI V2 does not adopt V1 sources, caches, credentials, or retention ownership. Before removing V1, stop V1 trigger admission, drain or intentionally terminate active jobs, explicitly retain or migrate history and artifacts, rotate runner and admin credentials, verify V2 readiness, storage, source delivery, and rollback, and only then remove V1 routes, collections, credentials, and object retention ownership.

Write administration uses Authorization: Bearer $GIT_ADMIN_TOKEN with JSON request bodies:

  • GET /api/v1/admin/operations returns a no-store operational snapshot covering repository visibility, retained bundle/LFS/source/release/npm/generic/OCI-package bytes, CI runners/jobs/artifacts/caches, dispatch backlogs, merge and webhook failures, configured storage limits, alerts, and the latest 20 maintenance runs;
  • POST /api/v1/repositories creates an empty native repository;
  • POST /api/v1/users creates a Git user;
  • PUT /api/v1/users/:username/status enables or disables a user;
  • POST /api/v1/users/:username/tokens issues a user access token whose plaintext is returned once;
  • DELETE /api/v1/users/:username/tokens/:tokenId revokes a user access token;
  • POST /api/v1/users/:username/ssh-keys registers an Ed25519, ECDSA, or RSA public key;
  • GET /api/v1/users/:username/ssh-keys lists key metadata and fingerprints without returning key material;
  • DELETE /api/v1/users/:username/ssh-keys/:keyId revokes a key;
  • PUT /api/v1/organizations/:org/members/:username assigns an owner, maintainer, developer, or reader role;
  • DELETE /api/v1/organizations/:org/members/:username removes membership;
  • POST /api/v1/repositories/:org/:repo/tokens issues a scoped repository token whose plaintext is returned once;
  • DELETE /api/v1/repositories/:org/:repo/tokens/:tokenId revokes a token;
  • PUT /api/v1/repositories/:org/:repo/visibility publishes or privatizes a repository;
  • GET|POST /api/v1/repositories/:org/:repo/releases lists or creates native releases for existing Git tags;
  • PUT|DELETE /api/v1/repositories/:org/:repo/releases/:tag updates or deletes a native release;
  • POST /api/v1/repositories/:org/:repo/releases/:tag/assets/:name streams a fixed-length release asset into integrity-verified object storage;
  • DELETE /api/v1/repositories/:org/:repo/releases/:tag/assets/:assetId deletes a release asset;
  • GET|POST /api/v1/repositories/:org/:repo/webhooks lists or creates signed repository webhooks;
  • DELETE /api/v1/repositories/:org/:repo/webhooks/:webhookId deletes a webhook and fails its pending deliveries;
  • GET /api/v1/repositories/:org/:repo/webhook-deliveries lists the latest durable delivery records;
  • POST /api/v1/repositories/:org/:repo/webhook-deliveries/:deliveryId/redeliver explicitly retries a completed or failed delivery.

Operational state and visibility totals use bounded SmartData grouped pages. Independent collections are queried in parallel rather than in one cross-collection transaction, so the result is operationally coherent but not a transactionally point-in-time snapshot. Queries request a two-second MongoDB limit, and projected dispatch/quota scans fail closed beyond 100,000 documents.

Published native releases replace the tag-derived public release for the same tag while preserving other tag releases. Assets download from GET /releases/download/:org/:repo/:releaseId/:assetId/:name; access follows repository visibility, and responses include the verified SHA-256 digest. Draft releases and their assets are never exposed publicly. Uploads use staged promotion, independent size and digest verification, atomic per-repository accounting, and restart recovery without filesystem persistence.

Webhook request bodies are stable JSON. Each request includes X-Foss-Event, a unique X-Foss-Delivery, and X-Foss-Signature-256: sha256=<hex HMAC>. The configured secret is encrypted at rest and is never returned by the administration API. Push deliveries are persisted before Smart HTTP or SSH reports a successful push; delivery itself runs from a leased, bounded-retry outbox.

Token issuance accepts one or both of the read and write permissions. Omitting permissions preserves the read/write default:

{"label":"deployment","permissions":["read"]}

Repository tokens are stored only as SHA-256 hashes. Public repositories clone anonymously. Private clone/fetch requires read; pushes require write. The token is accepted as a Basic-auth password or bearer token:

git remote add origin https://code.foss.global/org/repo.git
git fetch origin
git push origin main

For Basic authentication, use git as the username and the repository token as the password through an appropriate Git credential helper.

The same code.foss.global listener exposes a Gitea-compatible npm registry at /api/packages/:owner/npm/. Public package metadata and tarballs are readable anonymously. Private reads require organization read permission; publishing, dist-tag mutations, and unpublishing require write. Use a user access token issued above for a user who belongs to the target organization:

@foss.global:registry=https://code.foss.global/api/packages/foss.global/npm/
//code.foss.global/api/packages/foss.global/npm/:_authToken=${FOSS_GLOBAL_TOKEN}
always-auth=true

The registry supports scoped and unscoped packages with pnpm publish, pnpm install, pnpm view, pnpm search, pnpm dist-tag, and pnpm unpublish. For example:

pnpm publish --access public
pnpm add @foss.global/example
pnpm dist-tag add @foss.global/example@1.0.0 stable
pnpm unpublish @foss.global/example@1.0.0 --force

Published tarballs are staged, independently verified against SHA-1 and SHA-512 metadata, promoted to object storage, and atomically charged to the organization quota. Package metadata, versions, visibility, tags, and quotas live in SmartData; interrupted uploads and deletions recover without filesystem persistence.

The same listener also implements the Gitea generic package protocol at /api/packages/:owner/generic/:package/:version/:filename. Upload and delete operations accept a user token as a Basic-auth password or bearer token and require organization write permission. Public files download anonymously; private packages require read. New packages are public unless the first upload sends X-Package-Visibility: private:

curl --user "publisher:${FOSS_GLOBAL_TOKEN}" \
  --upload-file ./artifact.tar.gz \
  https://code.foss.global/api/packages/foss.global/generic/example/1.0.0/artifact.tar.gz

curl --fail --output artifact.tar.gz \
  https://code.foss.global/api/packages/foss.global/generic/example/1.0.0/artifact.tar.gz

curl --user "publisher:${FOSS_GLOBAL_TOKEN}" --request DELETE \
  https://code.foss.global/api/packages/foss.global/generic/example/1.0.0

Uploads require Content-Length, reject transfer/content encodings, and support X-Checksum-Sha256: <hex> or Digest: sha-256=<base64> verification. Files are immutable within a package version, staged and independently verified in object storage, atomically quota-accounted, and recovered after interrupted uploads or deletions. Package/file metadata and quotas live in SmartData; file payloads live in SmartBucket.

The same listener is also an OCI Distribution registry under /v2/. Repository names use {owner}/{image} and may contain additional lowercase path segments. A user access token for a member of the owner organization is accepted as the Docker password:

docker login code.foss.global --username publisher
docker tag example:1.0.0 code.foss.global/foss.global/example:1.0.0
docker push code.foss.global/foss.global/example:1.0.0
docker pull code.foss.global/foss.global/example:1.0.0

The registry implements resumable and monolithic blob uploads, same-owner cross-repository mounts, blob and manifest pull/HEAD/delete, case-insensitive tags, paginated tag listing, OCI referrers with artifact-type filtering, and Docker/OCI image manifests and indexes. New repositories are public by default. An authenticated manifest PUT can set X-Package-Visibility: private; private pulls require organization read permission and all pushes/deletes require write.

Blob chunks, final blobs, and exact manifest bytes are staged and independently SHA-256 verified in SmartBucket. Repository metadata, content links, upload sessions, tags, visibility, and owner quota reservations live in SmartData. OCI quota admission uses one atomic numeric expression over retained, reserved, and requested bytes, so concurrent reservations cannot exceed the owner budget or fail from retry exhaustion. Startup and scheduled maintenance recover abandoned uploads and crash-interrupted deletions without filesystem persistence. Docker push and pull interoperability is covered by the Mongo-backed integration suite.

The website exposes first-class package discovery and management at https://foss.global/#/packages. Anonymous discovery includes public npm, generic, and OCI packages across owners. Supplying an organization filter and user access token also includes that owner's private packages. Package detail views show versions, files or image tags, retained storage, exact digests, and ready-to-copy client commands. Organization writers can change visibility and delete npm versions, generic files, or OCI tags. The browser sends tokens only in same-origin typed requests and keeps them in component memory rather than filesystem or browser persistence.

SSH accepts only the git username and registered public keys. Public repositories require a valid active user key; private reads require at least the organization reader role, and pushes require at least developer. Shells, PTYs, forwarding, agents, subsystems, and arbitrary commands are rejected. Register the user's OpenSSH public key, then use the advertised origin:

git remote add ssh-origin ssh://git@code.foss.global:29460/org/repo.git
git fetch ssh-origin
git push ssh-origin main

Production must route code.foss.global through the platform TLS ingress to port 3002 and forward public raw TCP port 29460 to the same backend's internal port 29419 when SSH is enabled. Public TCP port 29419 belongs to the Cloudron instance and must not be claimed by this workload. The Rust Git transport binds only to an operating-system-assigned loopback port and accepts private upload-pack and receive-pack solely from the per-process ingress token; it is never the public listener. Keep write mode disabled until object-store credentials are trusted and the exact production image has passed HTTP and SSH clone, push, snapshot, restart, and restore smoke tests.

The source-controlled Cloudly declaration models this as one service with container ports 3000, 3001, 3002, and 29419. foss.global targets port 3000 and code.foss.global targets port 3002; both HTTP routes verify /healthz. Port 3001 is the CI V1 runner endpoint and must be exposed through the port-targeted TLS origin configured by CI_CONTROL_PLANE_PUBLIC_BASE_URL. The current declaration does not expose a separate CI V2 listener; enabling V2 in a deployment requires assigning and declaring a distinct container port and routing its credential-free HTTPS origin directly to that port. Internal port 29419 is raw SSH; DcRouter must expose it as public TCP 29460 for this same backend rather than introducing another repository or service.

Testing

Run the automated test suite:

pnpm test

The default suite includes disposable-Mongo CI V2, migration, catalog, and snapshot tests. Additional full Git/package lifecycle tests are enabled through CI_TEST_MONGODB_URL; each creates and removes a unique database and temporary resources:

CI_TEST_MONGODB_URL=mongodb://127.0.0.1:27017 pnpm test

Durable SSH push coverage additionally uses CI_TEST_S3_ENDPOINT, CI_TEST_S3_PORT, CI_TEST_S3_ACCESS_KEY, and CI_TEST_S3_ACCESS_SECRET. It creates and removes a unique database, bucket, repository, and temporary SSH keys.

Project Structure

./
├── ts/             # CLI source files
├── ts_web/         # Frontend source files
├── html/           # Static HTML templates
├── assets/         # Static assets (images, styles, etc.)
├── dist_ts/        # Compiled CLI output
├── dist_serve/     # Bundled website for serving
├── cli.js          # Node.js CLI entrypoint
├── cli.ts.js       # TypeScript CLI entrypoint
└── readme.md       # Project README

Module/Plugin Import Guidelines

CLI code imports modules via a central plugin file:

import * as plugins from './ffb.plugins.js';

Web code generally imports directly from packages or uses ts_web/plugins.ts when applicable.

Contributing

Contributions are welcome! To contribute:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/YourFeature)
  3. Commit your changes (git commit -m "Add awesome feature")
  4. Push to your fork (git push origin feature/YourFeature)
  5. Open a pull request against the main branch

Please follow the existing code style and run pnpm build before submitting.

License

This project is UNLICENSED. See package.json for details.

Contact / Support

S
Description
No description provided
Readme
2.2 MiB
Languages
TypeScript 99.8%
HTML 0.1%