🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

ossbridge

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ossbridge

CLI for bidirectional sync between a private monorepo and a public OSS mirror

latest
Source
npmnpm
Version
0.3.0
Version published
Maintainers
1
Created
Source

ossbridge

A CLI for bidirectional sync between a private canonical monorepo and a public OSS mirror. Manages the full lifecycle of external contributions: validation, merge, sync, and attribution.

Why ossbridge?

Managing OSS contributions when your canonical repo is private is painful. You need to:

  • Accept PRs on the public repo without exposing secrets
  • Run full validation in the private repo
  • Preserve contributor attribution across the sync
  • Close OSS PRs automatically after merge
  • Handle failures, race conditions, and edge cases

This typically means hundreds of lines of YAML spread across multiple workflows, with no tests, no type safety, and failures that manifest as PRs stuck in weird states.

ossbridge encapsulates this complexity in a single, testable CLI. Your workflows become thin declarations. The state machine is explicit. Failures are clear.

Quick Start

1. Create config files

Create ossbridge.json at the root of your OSS package:

{
  "schema": "ossbridge/v1",
  "privateRepo": "yourorg/private-monorepo",
  "ossRepo": "yourorg/oss-repo",
  "ossPath": "packages/mylib",
  "maintainers": ["@yourorg/maintainers", "alice", "bob"],
  "triggerComment": "/run-private-tests",
  "requiredChecks": ["oss-quick-ci"],
  "auth": {
    "privateToken": "OSSBRIDGE_PRIVATE_TOKEN",
    "ossToken": "OSSBRIDGE_OSS_TOKEN"
  }
}

At the private repo root, create a ref that points to the OSS package:

{
  "schema": "ossbridge/v1",
  "ref": "packages/mylib"
}

The config lives in the OSS package because the OSS repo can only see files within its folder. The private repo uses a ref so the CLI knows where to find it.

2. Set up secrets

The auth block specifies which environment variable names the CLI reads at runtime. Add matching GitHub secrets to both repos:

TokenScopes
OSSBRIDGE_PRIVATE_TOKENrepo
OSSBRIDGE_OSS_TOKENrepo, write:discussion

3. Add workflows

Wire up your GH action workflow yaml files to use the cli. This will be company and project specific in most cases, but see example-monorepo/ for a complete working setup with all workflow files, configs, and a step-by-step setup guide.

How It Works

Lifecycle

A contribution moves through eight steps across both repos:

  • Contributor opens a PR on the OSS repo. Standard CI runs (lint, tests) on OSS project without access to secrets.

  • Maintainer triggers validation by commenting the configured trigger phrase (e.g. /run-private-tests). The dispatch-pr command (OSS repo) verifies the commenter is a maintainer, confirms required checks have passed, records the PR's HEAD SHA, labels the PR ossbridge:accepted, and dispatches an ossbridge-import event to the private repo.

  • Private repo imports the PR. The import-pr command (private repo) fetches the PR's commits, remaps file paths from OSS root into the monorepo subtree (/ → {ossPath}/), creates a branch ossbridge/{pr-number}, and opens a PR titled [OSS #{n}] {title} against private main. The OSS PR is labeled ossbridge:validating.

  • Full CI runs in the private repo with secret access — integration tests, e2e, etc.

  • Results are reported back. The report-result command (private repo) reads the CI conclusion, updates the state comment on the OSS PR, and sets ossbridge:validated or ossbridge:failed.

  • Maintainer reviews and merges the private PR. Before merge completes, verify-merge (private repo, wired as a required status check) confirms the OSS PR hasn't changed since validation (SHA match), is still open, and has the ossbridge:validated label.

  • Changes sync to OSS. On push to private main, sync-downstream (private repo) identifies commits touching the subtree, remaps paths back ({ossPath}/ → /), and pushes to OSS main. Original author attribution is preserved — git blame shows the contributor on both repos.

  • OSS PR closes automatically. On push to OSS main, close-synced-prs (OSS repo) finds PRs whose changes have landed, posts a thank-you comment with commit links, removes all ossbridge:* labels, and closes the PR.

State Machine

PRs move through states tracked via GitHub labels:

[opened] → [ossbridge:accepted] → [ossbridge:validating] → [ossbridge:validated] → [closed]
                                                          ↘
                                                            [ossbridge:failed]

Command Reference

All commands read ossbridge.json from the repository root by default. Use --config <path> to override.

dispatch-pr

Runs in: OSS repo | Trigger: issue_comment

Preconditions (all must hold or exits 1):

  • Comment body matches triggerComment from config
  • Commenter is in maintainers list (supports @org/team slugs)
  • All requiredChecks have passed on the PR's HEAD
  • PR is open
  • PR has no existing ossbridge:* label (prevents double-dispatch)

Effects:

  • Creates a comment on the OSS PR containing: contributor notification + embedded state JSON (records HEAD SHA, acceptor, timestamp)
  • Adds ossbridge:accepted label
  • Dispatches ossbridge-import event to private repo with {ossPrNumber, ossPrSha} payload

Exit codes: 0 dispatched, 1 precondition failed

import-pr

Runs in: Private repo | Trigger: repository_dispatch type ossbridge-import

Preconditions:

  • OSS PR is open
  • OSS PR HEAD SHA matches the SHA from the dispatch payload (detects if PR was updated after trigger)
  • No existing private PR for this OSS PR (unless --force)

Effects:

  • Creates branch ossbridge/{oss-pr-number} in private repo
  • Opens PR titled [OSS #{n}] {title} against private main, body contains ossbridge metadata and file list with remapped paths
  • Updates state comment on OSS PR with private PR link
  • Sets ossbridge:validating label on OSS PR
  • Comments on OSS PR with link to private PR

Flags: --force re-import even if private PR exists

Exit codes: 0 private PR created/updated, 1 import failed

report-result

Runs in: Private repo | Trigger: workflow_run on ossbridge/* branches

Preconditions:

  • Private PR body contains ossbridge metadata
  • OSS repo in metadata matches config

Effects:

  • Updates state comment on OSS PR with validation result and timestamp
  • Sets ossbridge:validated or ossbridge:failed label (replaces previous ossbridge label)
  • Posts pass/fail notification comment on OSS PR (with failure details if applicable)

Flags: --passed / --failed override the CI conclusion (for manual recovery)

Note: skipped CI conclusion is treated as passed.

Exit codes: 0 result reported, 1 could not determine result or post status

verify-merge

Runs in: Private repo | Trigger: required status check (PR check or merge queue)

Preconditions:

  • Private PR body contains ossbridge metadata

Checks (any failure exits 1 and blocks merge):

  • OSS PR is still open
  • OSS PR HEAD SHA matches the SHA recorded at dispatch time
  • ossbridge:validated label is present (not ossbridge:failed, not ossbridge:validating)

Effects on failure:

  • SHA mismatch: posts "Validation Invalidated" comment on OSS PR showing expected vs current SHA

Exit codes: 0 safe to merge, 1 not safe

Wire this as a required status check to prevent merging stale validations.

sync-downstream

Runs in: Private repo | Trigger: push to main

Effects:

  • Compares commits between previous sync point and current HEAD
  • Filters to commits that touch files under ossPath
  • For each relevant commit: remaps paths {ossPath}/* → /*, preserves author attribution
  • Pushes to OSS repo main

Exit codes: 0 sync completed (or nothing to sync), 1 sync failed

close-synced-prs

Runs in: OSS repo | Trigger: push to main

Effects:

  • Finds open PRs with ossbridge:validated label
  • For each PR, checks if its changes have landed in main (handles both regular and squash merges via commit comparison)
  • Posts thank-you comment with canonical and mirrored commit links
  • Removes all ossbridge:* labels
  • Closes the PR

Flags: --pr {n} close a specific PR

Exit codes: 0 PRs closed (or none to close), 1 failed to close

status

Runs in: Either repo | Trigger: manual

Inspect PR state for debugging. Reads state from OSS PR comments and labels, discovers private PR by branch name if no state exists.

bunx ossbridge status --pr 42
OSS PR #42: Add custom validators
  State: open
  SHA: abc123def456
  Phase: validating
  Accepted by: alice at 2025-01-15T10:30:00Z
  Private PR: #17 (https://github.com/yourorg/private-monorepo/pull/17)
  Labels: ossbridge:validating
  Validation started: 2025-01-15T10:30:12Z

Configuration

Full config

{
  "schema": "ossbridge/v1",

  "privateRepo": "yourorg/private-monorepo",
  "ossRepo": "yourorg/oss-repo",
  "ossPath": "packages/mylib",

  "maintainers": ["@yourorg/maintainers", "alice", "bob"],
  "triggerComment": "/run-private-tests",
  "requiredChecks": ["oss-quick-ci"],

  "mergeMethod": "squash",
  "squashCommitIncludesHistory": true,

  "labels": {
    "accepted": "ossbridge:accepted",
    "validating": "ossbridge:validating",
    "validated": "ossbridge:validated",
    "failed": "ossbridge:failed"
  },

  "auth": {
    "privateToken": "OSSBRIDGE_PRIVATE_TOKEN",
    "ossToken": "OSSBRIDGE_OSS_TOKEN"
  },

  "notifications": {
    "validationStarted": "## Private Validation Started\n\n...",
    "validationPassed": "## Validation Passed\n\n...",
    "validationFailed": "## Validation Failed\n\n{failureDetails}",
    "prClosed": "## Merged!\n\n..."
  }
}

Field reference

FieldTypeRequiredDescription
schemastringyesMust be "ossbridge/v1"
privateRepostringyesowner/repo format
ossRepostringyesowner/repo format
ossPathstringyesPath within private repo that maps to OSS root
maintainersstring[]yesGitHub usernames or @org/team slugs authorized to trigger validation
triggerCommentstringyesComment text that triggers validation
requiredChecksstring[]yesStatus checks that must pass before dispatch
mergeMethodstringno"squash" (default), "merge", or "rebase"
squashCommitIncludesHistorybooleannoInclude original commit messages in squash body (default: true)
labelsobjectnoCustom label names (defaults: ossbridge:accepted, etc.)
auth.privateTokenstringyesEnv var name for private repo token
auth.ossTokenstringyesEnv var name for OSS repo token
notificationsobjectnoCustom notification templates (see variables below)

Notification template variables:

VariableDescription
{ossPrNumber}OSS PR number
{privatePrNumber}Private PR number
{privatePrUrl}URL to private validation PR
{failureDetails}CI failure logs
{triggerComment}The configured trigger comment
{privateCommitUrl}URL to canonical commit
{ossCommitUrl}URL to synced commit
{maintainer}Username who triggered validation

Config resolution

  • --config <path> flag
  • ossbridge.json in current working directory
  • ossbridge.json in repository root (detected via git)

Ref configs are automatically followed to load the actual configuration.

CI Integration

Each repo gets an ossbridge.yml workflow. The OSS repo handles inbound PRs (dispatch-pr on comment, close-synced-prs on push to main). The private repo handles import, validation, and sync (import-pr on dispatch, report-result on workflow completion, sync-downstream on push to main). A separate ossbridge-verify.yml wires verify-merge as a required check.

Minimal OSS repo workflow:

name: ossbridge
on:
  issue_comment:
    types: [created]
  push:
    branches: [main]

jobs:
  dispatch-pr:
    if: github.event_name == 'issue_comment' && github.event.issue.pull_request
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v1
      - run: bunx ossbridge dispatch-pr
        env:
          OSSBRIDGE_PRIVATE_TOKEN: ${{ secrets.OSSBRIDGE_PRIVATE_TOKEN }}
          OSSBRIDGE_OSS_TOKEN: ${{ secrets.OSSBRIDGE_OSS_TOKEN }}

See example-monorepo/ for the complete set of workflows for both repos, including the step-by-step setup guide.

Error Handling and Recovery

FailureBehavior
Maintainer not authorizeddispatch-pr exits 1, posts explanatory comment
Required checks not passeddispatch-pr exits 1, posts which checks are missing
PR already in workflowdispatch-pr exits 1 (duplicate-dispatch guard)
OSS PR closed during validationverify-merge exits 1, blocks merge
OSS PR updated after validationverify-merge exits 1, posts "Validation Invalidated" with SHA diff
Private CI failsreport-result sets ossbridge:failed label, posts failure details
Sync conflictsync-downstream exits 1
Missing auth tokenAll commands exit 1, message indicates which env var is missing

Manual recovery

# Force re-import (clears existing private PR)
bunx ossbridge import-pr --force --pr 42

# Manually mark as passed
bunx ossbridge report-result --passed --pr 42

# Manually close a PR that landed
bunx ossbridge close-synced-prs --pr 42

Limitations

  • Single subtree only — one directory to one OSS repo
  • GitHub only — no GitLab/Bitbucket support
  • No merge conflict resolution — sync fails on conflicts
  • Linear history assumed — complex merges may produce unexpected results

FAQs

Package last updated on 21 Feb 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts