Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ea663c2
adding hub-sync feature code
jefeish Aug 28, 2025
6457790
adjusting ui
jefeish Sep 1, 2025
498bbbd
hub improvements
jefeish Sep 10, 2025
dad3fe8
Add ui screen
jefeish Sep 24, 2025
5188801
updated README
jefeish Oct 2, 2025
de8bab4
handle multiple changes as a batch
decyjphr Oct 3, 2025
fa00d78
Update index.js
decyjphr Oct 3, 2025
b87397c
Update index.js
decyjphr Oct 3, 2025
6b358e5
depup files in a push
decyjphr Oct 5, 2025
c971041
Update index.js
decyjphr Oct 5, 2025
ac8e195
moved the dedup logic
decyjphr Oct 5, 2025
8bc76fc
Update index.js
decyjphr Oct 5, 2025
a5ef531
improved ui
jefeish May 8, 2026
b6887a2
Start at 2.1.18-rc1 and add roles plugin and enhance settings integr…
decyjphr May 15, 2026
bdcc6b5
Add custom repository roles schema to settings.json
decyjphr May 15, 2026
1d739f9
Add sub-org reevaluation logic and smoke tests
decyjphr May 19, 2026
baaa9d5
Add external group linking functionality for teams and update smoke t…
decyjphr May 19, 2026
6ca72a7
feat: add disable_plugins configuration to settings schema
decyjphr May 24, 2026
3cac68b
fix: add action.msg to dedup key so multiple disable_plugins NopComma…
decyjphr May 24, 2026
6938bf2
merge ydhav-issue-fix
jefeish May 26, 2026
a294cbd
feat: add support for additive_plugins in settings
decyjphr May 26, 2026
d03062a
fix: update .gitignore to ignore all .env files
decyjphr May 27, 2026
3312795
added base_url support
jefeish Jun 1, 2026
bfbd874
updated docs
jefeish Jun 1, 2026
4cb5e10
fixed sync log page
jefeish Jun 1, 2026
fa5020e
fix: update app.yml to remove empty line and add organization custom …
decyjphr Jun 2, 2026
d9be605
Refactor Variables Plugin: Simplify methods and add NopCommand support
decyjphr Jun 4, 2026
6a38988
fix: update variables handling in smoke test and add new repository Y…
decyjphr Jun 7, 2026
16b9375
Added PR989 changes
decyjphr Jun 7, 2026
1892ac7
Add reverse settings generator (issue #994)
decyjphr Jun 13, 2026
5fac715
feat: enhance smoke tests with custom repository roles and rulesets
decyjphr Jun 17, 2026
b250312
fix: enhance ruleset handling in MergeDeep and add tests for required…
decyjphr Jun 17, 2026
2bfc2e8
test: add ruleset comparison tests for required_reviewers and unnamed…
decyjphr Jun 17, 2026
e4498f1
added architecture diagram
jefeish Jun 18, 2026
79a8d43
hub-sync ui update
jefeish Jun 18, 2026
2d2f92f
feat: implement name-based resolution for ruleset bypass actors and r…
decyjphr Jun 23, 2026
2876b3f
Fix suborg-applied settings not removed when targeting rules change
decyjphr Jun 23, 2026
50fef03
Merge remote-tracking branch 'origin/decyjphr-fix-suborg-targeting-re…
jefeish Jun 23, 2026
4b9c44e
mergeConfig added
jefeish Jun 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,27 @@

# Uncomment this to get GitHub comments for the Pull Request Workflow.
# ENABLE_PR_COMMENT=true

# ADMIN_REPO=safe-settings-config
CONFIG_PATH=.github
SETTINGS_FILE_PATH=settings.yml

# Configuration support for Hub-Sync safe-settings feature
# SAFE_SETTINGS_HUB_REPO=safe-settings-config-master
# SAFE_SETTINGS_HUB_ORG=foo-training
# A subfolder under 'CONFIG_PATH' where the 'organizations/<org>/<repo>' structure is found
# SAFE_SETTINGS_HUB_PATH=safe-settings
# SAFE_SETTINGS_HUB_DIRECT_PUSH=true



# ┌────────────── second (optional)
# │ ┌──────────── minute
# │ │ ┌────────── hour
# │ │ │ ┌──────── day of month
# │ │ │ │ ┌────── month
# │ │ │ │ │ ┌──── day of week
# │ │ │ │ │ │
# │ │ │ │ │ │
# * * * * * *
# CRON=* * * * * # Run every minute
83 changes: 83 additions & 0 deletions docs/hubSyncHandler/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Safe Settings Organization Sync & Dashboard

This feature provides a centralized approach to managing the Safe-Settings Admin Repo, allowing Safe-Settings configurations to be sync'd across multiple ORGs.

## Overview

This feature adds a hub‑and‑spoke synchronization capability to Safe Settings.

One central **master admin repository** (the hub) serves as the authoritative source of configuration which is automatically propagated to each organization’s **admin repository** (the spokes).

**Note:** When something changes in the central repo, only those changed files are copied to each affected ORG’s admin repo, so everything stays in sync with little manual work.

## Sync Lifecycle (High Level)

```mermaid
graph TD
A0(PR Closed) --> A1(HUB Admin Repo)
A1(ORG Admin Repo) --> B(ORG Admin Repo)
A1(HUB Admin Repo) --> C(ORG Admin Repo)
A1(HUB Admin Repo) --> D(ORG Admin Repo)
```

## Environment Variables & Inputs

Environment variables specific to the 'Sync-Feature'

| Name | Purpose | Default |
|------|---------|---------|
| `SAFE_SETTINGS_HUB_REPO` | Repo for master safe-settings contents | admin-master |
| `SAFE_SETTINGS_HUB_ORG` | Organization that hold the Repo | admin-master-org |
| `SAFE_SETTINGS_HUB_PATH` | source folder | .github/safe-settings |
| `SAFE_SETTINGS_HUB_DIRECT_PUSH` | Use a PR or direct commit | false |


---
---

## Hub Sync Scenarios

1. Sync the `Hub Admin Repo` changes to a `Safe-Settings Admin Repo` in **the same ORG** as the Hub Admin Repo.

2. Sync the `Hub Admin changes` to a `Safe-Settings Admin Repo` in **a different ORG**.

3. _`'Global'`_ `Hub Admin Repo` updates.
Changes will `applied to all Organization`

---

## Safe-Settings Hub API endpoints

### API Endpoints

The following table summarizes the Safe Settings API endpoints:

| Endpoint | Method | Purpose | Example Usage |
|------------------------------------------|--------|------------------------------------------------------|---------------|
| `/api/safe-settings/installation` | GET | Organization installation, repo, and sync status | Fetch org status |
| `/api/safe-settings/hub/content` | GET | List hub repo files/directories | List hub files |
| `/api/safe-settings/hub/content/*` | GET | Fetch specific file or directory from hub repo | Get file content |
| `/api/safe-settings/hub/import` | POST | Import settings from orgs into the hub | Import org settings |
| `/api/safe-settings/env` | GET | App environment/config variables | Get env vars |

**Examples:**
- Fetch org installation status:
```http
GET /api/safe-settings/installation
```
- Import settings from orgs:
```http
POST /api/safe-settings/hub/import
Body: { "orgs": ["org1", "org2"] }
```
- List hub repo files:
```http
GET /api/safe-settings/hub/content?ref=main&recursive=true
```
- Get environment variables:
```http
GET /api/safe-settings/env
```

---

23 changes: 23 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,21 @@ const Glob = require('./lib/glob')
const ConfigManager = require('./lib/configManager')
const NopCommand = require('./lib/nopcommand')
const env = require('./lib/env')
const { setupRoutes } = require('./lib/routes')
const { initCache } = require('./lib/installationCache')
const { hubSyncHandler } = require('./lib/hubSyncHandler')

let deploymentConfig

module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) => {
let appSlug = 'safe-settings'

// Initialize all routes (static UI + API) via centralized module
setupRoutes(robot, getRouter)

// Initialize installation cache (env-controlled prefetch)
initCache(robot)

async function syncAllSettings (nop, context, repo = context.repo(), ref) {
try {
deploymentConfig = await loadYamlFileSystem()
Expand Down Expand Up @@ -521,6 +531,19 @@ module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) =>
return createCheckRun(context, pull_request, payload.pull_request.head.sha, payload.pull_request.head.ref)
})

/**
* @description Handle pull_request.closed events to support hub synchronization
* @param {Object} context - The context object provided by Probot
*/
robot.on('pull_request.closed', async context => {
try {
await hubSyncHandler(robot, context)
} catch (err) {
robot.log.error(`pull_request.closed handler failed: ${err && err.message ? err.message : err}`)
}
return null
})

robot.on(['check_suite.rerequested'], async context => {
robot.log.debug('Check suite was rerequested!')
return createCheckRun(context)
Expand Down
6 changes: 6 additions & 0 deletions lib/env.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
module.exports = {
ADMIN_REPO: process.env.ADMIN_REPO || 'admin',
SAFE_SETTINGS_HUB_REPO: process.env.SAFE_SETTINGS_HUB_REPO || 'admin-master',
SAFE_SETTINGS_HUB_ORG: process.env.SAFE_SETTINGS_HUB_ORG || 'admin-master-org',
SAFE_SETTINGS_HUB_DIRECT_PUSH: process.env.SAFE_SETTINGS_HUB_DIRECT_PUSH || 'false',
SAFE_SETTINGS_HUB_PATH: process.env.SAFE_SETTINGS_HUB_PATH || '.github/safe-settings',
APP_ID: process.env.APP_ID || null,
PRIVATE_KEY_PATH: process.env.PRIVATE_KEY_PATH || 'private-key.pem',
CONFIG_PATH: process.env.CONFIG_PATH || '.github',
SETTINGS_FILE_PATH: process.env.SETTINGS_FILE_PATH || 'settings.yml',
DEPLOYMENT_CONFIG_FILE_PATH: process.env.DEPLOYMENT_CONFIG_FILE || 'deployment-settings.yml',
Expand Down
Loading
Loading