{"id":48676816,"url":"https://github.com/joshjohanning/bulk-github-org-settings-sync-action","last_synced_at":"2026-05-14T18:01:21.430Z","repository":{"id":349860286,"uuid":"1204015522","full_name":"joshjohanning/bulk-github-org-settings-sync-action","owner":"joshjohanning","description":"🏢 Bulk configure GitHub organization settings across multiple orgs using a declarative YAML config","archived":false,"fork":false,"pushed_at":"2026-05-11T18:57:15.000Z","size":3996,"stargazers_count":0,"open_issues_count":8,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-11T19:03:00.251Z","etag":null,"topics":["actions","approval","github","issue-ops","issueops","javascript","node-action"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joshjohanning.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-07T15:56:43.000Z","updated_at":"2026-05-11T18:56:46.000Z","dependencies_parsed_at":"2026-05-11T19:01:10.319Z","dependency_job_id":null,"html_url":"https://github.com/joshjohanning/bulk-github-org-settings-sync-action","commit_stats":null,"previous_names":["joshjohanning/bulk-github-org-settings-sync-action"],"tags_count":13,"template":false,"template_full_name":"joshjohanning/nodejs-actions-starter-template","purl":"pkg:github/joshjohanning/bulk-github-org-settings-sync-action","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshjohanning%2Fbulk-github-org-settings-sync-action","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshjohanning%2Fbulk-github-org-settings-sync-action/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshjohanning%2Fbulk-github-org-settings-sync-action/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshjohanning%2Fbulk-github-org-settings-sync-action/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joshjohanning","download_url":"https://codeload.github.com/joshjohanning/bulk-github-org-settings-sync-action/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshjohanning%2Fbulk-github-org-settings-sync-action/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33037047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-14T02:00:06.663Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actions","approval","github","issue-ops","issueops","javascript","node-action"],"created_at":"2026-04-10T17:27:48.926Z","updated_at":"2026-05-14T18:01:21.389Z","avatar_url":"https://github.com/joshjohanning.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bulk GitHub Organization Settings Sync Action\n\n[![GitHub release](https://img.shields.io/github/release/joshjohanning/bulk-github-org-settings-sync-action.svg?logo=github\u0026labelColor=333)](https://github.com/joshjohanning/bulk-github-org-settings-sync-action/releases)\n[![Immutable releases](https://img.shields.io/badge/releases-immutable-blue?labelColor=333)](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/immutable-releases)\n[![GitHub marketplace](https://img.shields.io/badge/marketplace-Bulk%20GitHub%20Organization%20Settings%20Sync-blue?logo=github\u0026labelColor=333)](https://github.com/marketplace/actions/bulk-github-organization-settings-sync)\n[![CI](https://github.com/joshjohanning/bulk-github-org-settings-sync-action/actions/workflows/ci.yml/badge.svg)](https://github.com/joshjohanning/bulk-github-org-settings-sync-action/actions/workflows/ci.yml)\n[![Publish GitHub Action](https://github.com/joshjohanning/bulk-github-org-settings-sync-action/actions/workflows/publish.yml/badge.svg)](https://github.com/joshjohanning/bulk-github-org-settings-sync-action/actions/workflows/publish.yml)\n![Coverage](./badges/coverage.svg)\n\n🏢 Bulk configure GitHub organization settings across multiple orgs using a declarative YAML config\n\n## What's new\n\nPlease refer to the [release page](https://github.com/joshjohanning/bulk-github-org-settings-sync-action/releases) for the latest release notes.\n\n## Features\n\n- 🏷️ Sync custom property definitions across organizations\n- 📋 Sync organization-level rulesets across organizations\n- 🏷️ Sync issue type definitions across organizations\n- 🔧 Sync member privileges and repository policies across organizations\n- 🔒 Sync code security configurations across organizations\n- 🔒 Sync GitHub Actions security and policy settings across organizations\n- ✅ Support for all custom property types: `string`, `single_select`, `multi_select`, `true_false`, `url`\n- 🔍 Dry-run mode with change preview and intelligent change detection\n- 📋 Per-organization overrides via YAML configuration\n- 📊 Rich job summary with per-organization status table\n- 🌐 Support for GitHub.com, GHES, and GHEC\n\n## Usage Examples\n\n### Basic Usage\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    organizations: 'my-org,my-other-org'\n    custom-properties-file: './custom-properties.yml'\n    delete-unmanaged-properties: true\n    dry-run: ${{ github.event_name == 'pull_request' }} # dry run if PR\n```\n\n---\n\n## Authentication\n\n### GitHub App (Recommended)\n\nFor stronger security and higher rate limits, use a GitHub App:\n\n1. Create a GitHub App with the following permissions:\n   - **Organization Custom Properties**: Admin (required for managing custom property definitions)\n   - **Organization Administration**: Read and write (required for managing organization settings and rulesets)\n   - **Organization Issue Types**: Write (required for managing issue type definitions)\n2. Install it to your organization(s)\n3. Add `APP_ID` and `APP_PRIVATE_KEY` as repository secrets\n\n```yml\n- name: Generate GitHub App Token\n  id: app-token\n  uses: actions/create-github-app-token@v3\n  with:\n    app-id: ${{ secrets.APP_ID }}\n    private-key: ${{ secrets.APP_PRIVATE_KEY }}\n    owner: ${{ github.repository_owner }}\n\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ steps.app-token.outputs.token }}\n    # ... other inputs\n```\n\n### Personal Access Token\n\nAlternatively, use a PAT with `admin:org` scope:\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    # ... other inputs\n```\n\n---\n\n## Organization Selection Methods\n\nThis action supports two approaches for selecting which organizations to manage. Choose based on your needs:\n\n| Approach                                                                 | Best For                                                 | Configuration File                   |\n| ------------------------------------------------------------------------ | -------------------------------------------------------- | ------------------------------------ |\n| [**Option 1: Organization List**](#option-1-organization-list)           | Simple setup, same settings applied to all orgs          | `custom-properties.yml`              |\n| [**Option 2: Organizations File**](#option-2-organizations-file-orgsyml) | Per-org overrides, different settings for different orgs | `orgs.yml` + `custom-properties.yml` |\n\n---\n\n### Option 1: Organization List\n\nList organizations directly via the `organizations` input. All orgs receive the same settings defined via `custom-properties-file`.\n\n**Best for:** Applying identical settings across all organizations.\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    organizations: 'my-org, my-other-org, my-third-org'\n    custom-properties-file: './custom-properties.yml'\n```\n\n---\n\n### Option 2: Organizations File (`orgs.yml`)\n\nDefine organizations in a YAML file with optional per-org setting overrides. Common settings can still be defined via action inputs (including member privilege inputs and `custom-properties-file`) — per-org overrides layer on top (same pattern as [`bulk-github-repo-settings-sync-action`](https://github.com/joshjohanning/bulk-github-repo-settings-sync-action) where action inputs define global defaults and the YAML file provides per-item overrides).\n\n**Best for:** Managing multiple orgs with different settings, or when specific orgs need additional/different custom properties or member privileges.\n\n\u003e [!TIP]\n\u003e 📄 **See full example:** [sample-configuration/orgs.yml](sample-configuration/orgs.yml)\n\nCreate an `orgs.yml` file:\n\n```yaml\norgs:\n  - org: my-org\n    # No custom-properties → inherits all base properties from custom-properties-file\n    # No member-privileges → inherits all base settings from action inputs\n\n  - org: my-other-org\n    custom-properties-file: './config/custom-properties/other-org.yml' # Override base file for this org\n    rulesets-file: # Override rulesets for this org (YAML array)\n      - './config/rulesets/branch-protection.json'\n      - './config/rulesets/tag-protection.json'\n    delete-unmanaged-rulesets: true # Delete rulesets not in the config for this org\n    delete-unmanaged-properties: true # Override the action input for this org\n    custom-properties:\n      # Override \"team\" to add extra allowed values for this org\n      - name: team\n        value-type: single_select\n        required: true\n        description: 'The team that owns this repository'\n        allowed-values:\n          - platform\n          - frontend\n          - backend\n          - data-science # extra team only in this org\n        values-editable-by: org_actors\n    member-privileges:\n      # Override specific member privilege settings for this org\n      members-can-fork-private-repositories: true\n      members-can-create-internal-repositories: true # GHEC/GHES only\n```\n\n**Optional: `base-path`**\n\nUse the `base-path` top-level property to avoid repeating a common directory prefix for all file-path settings (`custom-properties-file`, `issue-types-file`, `rulesets-file`). Relative paths in per-org overrides are resolved relative to `base-path`. Absolute paths are left unchanged.\n\n```yaml\nbase-path: './config/'\norgs:\n  - org: my-org\n    custom-properties-file: 'custom-properties/base.yml' # resolved to ./config/custom-properties/base.yml\n    issue-types-file: 'issue-types/base.yml' # resolved to ./config/issue-types/base.yml\n    rulesets-file: 'rulesets/branch-protection.json' # resolved to ./config/rulesets/branch-protection.json\n  - org: my-other-org\n    custom-properties-file: 'custom-properties/other-org.yml'\n```\n\nUse in workflow:\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    organizations-file: './orgs.yml'\n    custom-properties-file: './config/custom-properties/base.yml' # Base properties for all orgs\n    rulesets-file: './config/rulesets/branch-protection.json, ./config/rulesets/tag-protection.json' # Base rulesets for all orgs\n    default-repository-permission: read # Base member privileges for all orgs\n    members-can-fork-private-repositories: false\n```\n\n**Settings Merging:**\n\nWhen using both `custom-properties-file` (base) and per-org `custom-properties` in the organizations file, settings are merged by property name. Per-org definitions override base definitions for the same property name; base properties not overridden are preserved:\n\n```yaml\n# custom-properties.yml (base):\n- name: team             # → applied to all orgs\n- name: cost-center      # → applied to all orgs\n\n# orgs.yml:\norgs:\n  - org: my-org          # gets: team + cost-center (base only)\n  - org: my-other-org\n    custom-properties:\n      - name: team       # overrides base \"team\" with different allowed-values\n                         # gets: team (overridden) + cost-center (from base)\n```\n\nThe same merging applies to member privilege inputs and per-org `member-privileges` — per-org settings override base settings with the same key; base settings not overridden are preserved:\n\n```yaml\n# action inputs (base): default-repository-permission=read, members-can-fork-private-repositories=false\n\n# orgs.yml:\norgs:\n  - org: my-org # gets: read + no fork (base only)\n  - org: my-other-org\n    member-privileges:\n      members-can-fork-private-repositories: true # override → fork allowed\n      # gets: read (from base) + fork allowed (overridden)\n```\n\n---\n\n## Syncing Custom Properties\n\nSync custom property definitions (schemas) to organizations. Properties define the metadata that can be set on repositories within the organization.\n\n\u003e [!TIP]\n\u003e 📄 **See full example:** [sample-configuration/custom-properties.yml](sample-configuration/custom-properties.yml)\n\nCreate a `custom-properties.yml` file:\n\n```yaml\n- name: team\n  value-type: single_select\n  required: true\n  description: 'The team that owns this repository'\n  allowed-values:\n    - platform\n    - frontend\n    - backend\n    - devops\n    - security\n  values-editable-by: org_actors\n\n- name: environment\n  value-type: multi_select\n  required: false\n  description: 'Deployment environments for this repository'\n  allowed-values:\n    - production\n    - staging\n    - development\n  values-editable-by: org_and_repo_actors\n\n- name: is-production\n  value-type: true_false\n  required: false\n  default-value: 'false'\n  description: 'Whether this repository is used in production'\n  values-editable-by: org_actors\n\n- name: cost-center\n  value-type: string\n  required: false\n  description: 'Cost center code for billing'\n  values-editable-by: org_actors\n```\n\n**Behavior:**\n\n- If a custom property doesn't exist in the org, it is created\n- If it exists but differs from the config, it is updated\n- If content is identical, no changes are made\n- With `delete-unmanaged-properties: true`, properties not in the config are deleted\n\n### Custom Property Types\n\n| Type            | Description                     | Requires `allowed-values` |\n| --------------- | ------------------------------- | ------------------------- |\n| `string`        | Free-form text                  | No                        |\n| `single_select` | Single selection from a list    | Yes                       |\n| `multi_select`  | Multiple selections from a list | Yes                       |\n| `true_false`    | Boolean value                   | No                        |\n| `url`           | URL value                       | No                        |\n\n### Custom Property Fields\n\nEach custom property supports these fields:\n\n| Field                | Description                                         | Required    | Default      |\n| -------------------- | --------------------------------------------------- | ----------- | ------------ |\n| `name`               | Property name                                       | Yes         |              |\n| `value-type`         | Property type (`string`, `single_select`, etc.)     | Yes         |              |\n| `required`           | Whether a value is required for all repos           | No          | `false`      |\n| `description`        | Human-readable description                          | No          |              |\n| `default-value`      | Default value for new repositories                  | No          |              |\n| `allowed-values`     | List of allowed values (required for select types)  | Conditional |              |\n| `values-editable-by` | Who can edit: `org_actors` or `org_and_repo_actors` | No          | `org_actors` |\n\n### Delete Unmanaged Properties\n\nBy default, syncing custom properties will create or update the specified properties, but will not delete other properties that may exist in the organization. To delete all other properties not defined in the config, use `delete-unmanaged-properties`:\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    organizations: 'my-org'\n    custom-properties-file: './custom-properties.yml'\n    delete-unmanaged-properties: true\n```\n\n**Behavior with `delete-unmanaged-properties: true`:**\n\n- Creates properties that don't exist\n- Updates properties that differ from the config\n- **Deletes all other properties not defined in the config**\n- In dry-run mode, shows which properties would be deleted without actually deleting them\n\n---\n\n## Syncing Organization Rulesets\n\nSync organization-level rulesets across organizations. Rulesets define rules that apply to repositories within the organization (e.g., branch protection rules, tag rules). Each ruleset is defined in its own JSON file, and `rulesets-file` accepts comma-separated paths to sync multiple rulesets.\n\n\u003e [!TIP]\n\u003e 📄 **See full examples:** [sample-configuration/rulesets/](sample-configuration/rulesets/)\n\nCreate a JSON file for each ruleset (one ruleset per file):\n\n**`rulesets/branch-protection.json`:**\n\n```json\n{\n  \"name\": \"org-branch-protection\",\n  \"target\": \"branch\",\n  \"enforcement\": \"active\",\n  \"bypass_actors\": [\n    {\n      \"actor_id\": 5,\n      \"actor_type\": \"RepositoryRole\",\n      \"bypass_mode\": \"always\"\n    }\n  ],\n  \"conditions\": {\n    \"ref_name\": {\n      \"include\": [\"~DEFAULT_BRANCH\"],\n      \"exclude\": []\n    },\n    \"repository_name\": {\n      \"include\": [\"~ALL\"],\n      \"exclude\": []\n    }\n  },\n  \"rules\": [\n    {\n      \"type\": \"deletion\"\n    },\n    {\n      \"type\": \"non_fast_forward\"\n    },\n    {\n      \"type\": \"pull_request\",\n      \"parameters\": {\n        \"required_approving_review_count\": 1,\n        \"dismiss_stale_reviews_on_push\": true,\n        \"require_code_owner_review\": false,\n        \"require_last_push_approval\": false,\n        \"required_review_thread_resolution\": false,\n        \"automatic_copilot_code_review_enabled\": false\n      }\n    }\n  ]\n}\n```\n\n**`rulesets/tag-protection.json`:**\n\n```json\n{\n  \"name\": \"org-tag-protection\",\n  \"target\": \"tag\",\n  \"enforcement\": \"active\",\n  \"conditions\": {\n    \"ref_name\": {\n      \"include\": [\"~ALL\"],\n      \"exclude\": []\n    },\n    \"repository_name\": {\n      \"include\": [\"~ALL\"],\n      \"exclude\": []\n    }\n  },\n  \"rules\": [\n    {\n      \"type\": \"deletion\"\n    },\n    {\n      \"type\": \"non_fast_forward\"\n    }\n  ]\n}\n```\n\nSync both rulesets using comma-separated paths:\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    organizations: 'my-org'\n    rulesets-file: './rulesets/branch-protection.json, ./rulesets/tag-protection.json'\n```\n\n\u003e [!TIP]\n\u003e The JSON format matches the [GitHub REST API for organization rulesets](https://docs.github.com/en/rest/orgs/rules). You can export an existing ruleset from your organization via the API as a starting point, but exported responses may include read-only fields (e.g., `id`, `source`, `node_id`) that are automatically stripped before create/update operations.\n\n**Behavior:**\n\n- If a ruleset with the same name doesn't exist, it is created\n- If it exists but differs from the config, it is updated\n- If content is identical, no changes are made\n- With `delete-unmanaged-rulesets: true`, rulesets not matching any managed name are deleted\n\n### Per-Org Rulesets Override\n\nIn `orgs.yml`, use a YAML array to override rulesets for a specific org:\n\n```yaml\norgs:\n  - org: my-org\n    # inherits base rulesets-file from action input\n\n  - org: my-other-org\n    rulesets-file:\n      - './config/rulesets/branch-protection.json'\n      - './config/rulesets/tag-protection.json'\n    delete-unmanaged-rulesets: true\n```\n\n### Delete Unmanaged Rulesets\n\nBy default, syncing rulesets will create or update the specified rulesets, but will not delete other rulesets that may exist in the organization. To delete all other rulesets besides those being synced, use `delete-unmanaged-rulesets`:\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    organizations: 'my-org'\n    rulesets-file: './rulesets/branch-protection.json, ./rulesets/tag-protection.json'\n    delete-unmanaged-rulesets: true\n```\n\n**Behavior with `delete-unmanaged-rulesets: true`:**\n\n- Creates rulesets that don't exist\n- Updates rulesets that differ from the config\n- **Deletes all other rulesets not matching any managed ruleset name**\n- In dry-run mode, shows which rulesets would be deleted without actually deleting them\n\n---\n\n## Syncing Issue Types\n\nSync organization-level issue type definitions across organizations. Issue types define the categories (e.g., Bug, Feature, Task) that can be assigned to issues within the organization.\n\nCreate an `issue-types.yml` file:\n\n```yaml\n- name: Bug\n  description: 'Something is broken'\n  color: 'ff0000'\n\n- name: Feature\n  description: 'A new feature request'\n  color: '0e8a16'\n\n- name: Task\n  description: 'A unit of work'\n  color: 'fbca04'\n  is-enabled: true\n```\n\nUse in workflow:\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    organizations: 'my-org'\n    issue-types-file: './issue-types.yml'\n```\n\n**Behavior:**\n\n- If an issue type with the same name doesn't exist, it is created\n- If it exists but differs from the config, it is updated\n- If content is identical, no changes are made\n- With `delete-unmanaged-issue-types: true`, issue types not in the config are deleted\n\n### Issue Type Fields\n\nEach issue type supports these fields:\n\n| Field         | Description                              | Required | Default |\n| ------------- | ---------------------------------------- | -------- | ------- |\n| `name`        | Issue type name                          | Yes      |         |\n| `description` | Human-readable description               | No       |         |\n| `color`       | 6-character hex color code (without `#`) | No       |         |\n| `is-enabled`  | Whether the issue type is enabled        | No       | `true`  |\n\n### Per-Org Issue Types Override\n\nIn `orgs.yml`, you can define issue types per-org or use a separate file:\n\n```yaml\norgs:\n  - org: my-org\n    # inherits base issue-types-file from action input\n\n  - org: my-other-org\n    issue-types-file: './config/issue-types/other-org.yml'\n    delete-unmanaged-issue-types: true\n    issue-types:\n      - name: Bug\n        description: 'Critical bug'\n        color: 'ff0000'\n```\n\n### Delete Unmanaged Issue Types\n\nBy default, syncing issue types will create or update the specified types, but will not delete other issue types that may exist in the organization. To delete all other issue types not defined in the config, use `delete-unmanaged-issue-types`:\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    organizations: 'my-org'\n    issue-types-file: './issue-types.yml'\n    delete-unmanaged-issue-types: true\n```\n\n**Behavior with `delete-unmanaged-issue-types: true`:**\n\n- Creates issue types that don't exist\n- Updates issue types that differ from the config\n- **Deletes all other issue types not defined in the config**\n- In dry-run mode, shows which issue types would be deleted without actually deleting them\n\n---\n\n## Syncing Member Privileges\n\nSync organization-level member privilege settings (repository policies) across organizations. These control what members can do within the organization, such as creating repositories, forking private repos, and managing pages.\n\nSet member privilege settings directly as action inputs:\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    organizations: 'my-org'\n    default-repository-permission: read\n    members-can-create-repositories: true\n    members-can-fork-private-repositories: false\n    members-can-create-internal-repositories: false # GHEC/GHES only\n    web-commit-signoff-required: true\n    default-repository-branch: main\n```\n\n**Behavior:**\n\n- Only settings included in the config are managed — omitted settings remain unchanged\n- If a setting already matches the config, no API call is made\n- Settings are applied via a single `PATCH /orgs/{org}` call per organization\n- In dry-run mode, shows which settings would be changed without applying them\n\n### Member Privilege Settings\n\n| Setting                                       | Type    | Description                                                          |\n| --------------------------------------------- | ------- | -------------------------------------------------------------------- |\n| `default-repository-permission`               | string  | Default permission for org members: `read`, `write`, `admin`, `none` |\n| `members-can-create-repositories`             | boolean | Can members create repositories                                      |\n| `members-can-create-public-repositories`      | boolean | Can members create public repositories                               |\n| `members-can-create-private-repositories`     | boolean | Can members create private repositories                              |\n| `members-can-create-internal-repositories`    | boolean | Can members create internal repositories (GHEC/GHES only)            |\n| `members-can-fork-private-repositories`       | boolean | Can members fork private repositories                                |\n| `web-commit-signoff-required`                 | boolean | Require web UI commits to be signed off                              |\n| `members-can-create-pages`                    | boolean | Can members create GitHub Pages sites                                |\n| `members-can-create-public-pages`             | boolean | Can members create public GitHub Pages sites                         |\n| `members-can-create-private-pages`            | boolean | Can members create private GitHub Pages sites                        |\n| `members-can-invite-outside-collaborators`    | boolean | Can members invite outside collaborators                             |\n| `members-can-create-teams`                    | boolean | Can members create teams                                             |\n| `members-can-delete-repositories`             | boolean | Can members delete repositories                                      |\n| `members-can-change-repo-visibility`          | boolean | Can members change repository visibility                             |\n| `members-can-delete-issues`                   | boolean | Can members delete issues                                            |\n| `default-repository-branch`                   | string  | Default branch name for new repositories                             |\n| `deploy-keys-enabled-for-repositories`        | boolean | Whether deploy keys can be added to repositories                     |\n| `readers-can-create-discussions`              | boolean | Can users with read access create discussions                        |\n| `members-can-view-dependency-insights`        | boolean | Can members view dependency insights                                 |\n| `display-commenter-full-name-setting-enabled` | boolean | Display commenter full name in issues and PRs                        |\n\n### Per-Org Member Privilege Overrides\n\nIn `orgs.yml`, use `member-privileges` to override specific settings for an org:\n\n```yaml\norgs:\n  - org: my-org\n    # inherits base member privilege action inputs\n\n  - org: my-other-org\n    member-privileges:\n      members-can-fork-private-repositories: true # override base\n      members-can-create-internal-repositories: true # GHEC/GHES only\n```\n\n---\n\n## Syncing Code Security Configurations\n\nSync named code security configurations across organizations. These configurations define security feature enablement policies (e.g., Dependabot, secret scanning, code scanning) that can be applied to repositories.\n\n### Basic Usage\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    organizations: 'my-org,my-other-org'\n    code-security-configurations-file: './code-security-configurations.yml'\n```\n\n### Example Configuration File\n\n```yaml\n# code-security-configurations.yml\n- name: High risk settings\n  description: Security configuration for high risk repositories\n  advanced_security: enabled\n  dependency_graph: enabled\n  dependabot_alerts: enabled\n  dependabot_security_updates: enabled\n  code_scanning_default_setup: enabled\n  secret_scanning: enabled\n  secret_scanning_push_protection: enabled\n  private_vulnerability_reporting: enabled\n  enforcement: enforced\n\n- name: Standard settings\n  description: Security configuration for standard repositories\n  advanced_security: enabled\n  dependency_graph: enabled\n  dependabot_alerts: enabled\n  secret_scanning: enabled\n  secret_scanning_push_protection: enabled\n  private_vulnerability_reporting: enabled\n  enforcement: unenforced\n```\n\nAll enablement fields accept: `enabled`, `disabled`, or `not_set`. The `enforcement` field accepts: `enforced` or `unenforced`.\n\n### Optional Repository Attachment and Defaults\n\nYou can also configure how each code security configuration is applied:\n\n- `attach-scope`: attach to `all`, `all_without_configurations`, `public`, `private_or_internal`, or `selected` repositories\n- `selected-repository-ids`: optional repository IDs when `attach-scope: selected`\n- `selected-repositories`: optional repository names (for example `high-risk-service` or `app-api`) when `attach-scope: selected`\n- `selected-repositories-by-property`: optional list of `{property, value}` filters; any repo in the org matching any filter is included when `attach-scope: selected`\n- `default-for-new-repos`: set default for newly created repos (`all`, `none`, `public`, `private_and_internal`)\n\nExample:\n\n```yaml\n- name: High risk settings\n  description: Security configuration for high risk repositories\n  advanced_security: enabled\n  attach-scope: selected\n  selected-repositories: [high-risk-service, app-api]\n  default-for-new-repos: private_and_internal\n```\n\nOr select repositories by custom property:\n\n```yaml\n- name: High risk settings\n  description: Security configuration for high risk repositories\n  advanced_security: enabled\n  attach-scope: selected\n  selected-repositories-by-property:\n    - property: criticality\n      value: high\n  default-for-new-repos: private_and_internal\n```\n\n`selected-repository-ids`, `selected-repositories`, and `selected-repositories-by-property` can all be combined — matching repos from all three sources are merged into one set.\n\nIf multiple configurations use `attach-scope`, broader scopes are applied first and `selected` is applied last, so selected repositories can override broad assignments.\n\nFor `attach-scope`, the following combinations are invalid and will fail the run:\n\n- The same broad scope (`all`, `all_without_configurations`, `public`, `private_or_internal`) cannot appear on more than one configuration.\n- `all` cannot be combined with `all_without_configurations`, `public`, or `private_or_internal`.\n- `all_without_configurations` cannot be combined with `public` or `private_or_internal` (unconfigured repos in those visibility categories would be targeted by both).\n- `selected` may appear on multiple configurations, but each repository may only be targeted by one of them — overlapping repo sets across `selected`-scope configurations will fail the run.\n\nFor `default-for-new-repos`, values must not conflict:\n\n- `none` cannot be combined with any other default assignment.\n- `all` cannot be combined with `public` or `private_and_internal`.\n- You cannot define the same default target more than once.\n\n### Per-Org Code Security Configuration Overrides\n\nIn `orgs.yml`, use `code-security-configurations` to override specific configurations for an org:\n\n```yaml\norgs:\n  - org: my-org\n    # inherits base code-security-configurations-file as-is\n\n  - org: my-other-org\n    # code-security-configurations-file: './other-org-configs.yml' # use a different base file\n    code-security-configurations:\n      - name: High risk settings\n        description: Stricter settings for this org\n        advanced_security: enabled\n        secret_scanning: enabled\n        secret_scanning_push_protection: enabled\n        enforcement: enforced\n        attach-scope: all_without_configurations\n        default-for-new-repos: private_and_internal\n```\n\n### Delete Unmanaged Configurations\n\nSet `delete-unmanaged-code-security-configurations: true` to remove code security configurations not defined in the configuration file. Only custom (organization-owned) configurations are deleted — global GitHub-managed configurations are never touched.\n\nWhen `attach-scope` and/or `default-for-new-repos` are configured, the action also applies repository attachment and default assignment for that named configuration.\n\n\u003e [!NOTE]\n\u003e Requires a GitHub Advanced Security (GHAS) license for `advanced_security` features. Available on GitHub.com (GHEC) and GHES 3.x+.\n\n---\n\n## Action Inputs\n\n| Input                                           | Description                                                                         | Required | Default                 |\n| ----------------------------------------------- | ----------------------------------------------------------------------------------- | -------- | ----------------------- |\n| `github-token`                                  | GitHub token for API access (requires `admin:org` scope)                            | Yes      |                         |\n| `github-api-url`                                | GitHub API URL (e.g., `https://api.github.com` or `https://ghes.domain.com/api/v3`) | No       | `${{ github.api_url }}` |\n| `organizations`                                 | Comma-separated list of organization names                                          | No       |                         |\n| `organizations-file`                            | Path to YAML file containing organization settings configuration                    | No       |                         |\n| `custom-properties-file`                        | Path to a YAML file defining custom property schemas                                | No       |                         |\n| `delete-unmanaged-properties`                   | Delete custom properties not defined in the configuration file                      | No       | `false`                 |\n| `issue-types-file`                              | Path to a YAML file defining issue type definitions                                 | No       |                         |\n| `delete-unmanaged-issue-types`                  | Delete issue types not defined in the configuration file                            | No       | `false`                 |\n| `default-repository-permission`                 | Default permission for org members: `read`, `write`, `admin`, `none`                | No       |                         |\n| `members-can-create-repositories`               | Whether members can create repositories                                             | No       |                         |\n| `members-can-create-public-repositories`        | Whether members can create public repositories                                      | No       |                         |\n| `members-can-create-private-repositories`       | Whether members can create private repositories                                     | No       |                         |\n| `members-can-create-internal-repositories`      | Whether members can create internal repositories (GHEC/GHES only)                   | No       |                         |\n| `members-can-fork-private-repositories`         | Whether members can fork private repositories                                       | No       |                         |\n| `web-commit-signoff-required`                   | Whether web UI commits require signoff                                              | No       |                         |\n| `members-can-create-pages`                      | Whether members can create GitHub Pages sites                                       | No       |                         |\n| `members-can-create-public-pages`               | Whether members can create public GitHub Pages sites                                | No       |                         |\n| `members-can-create-private-pages`              | Whether members can create private GitHub Pages sites                               | No       |                         |\n| `members-can-invite-outside-collaborators`      | Whether members can invite outside collaborators                                    | No       |                         |\n| `members-can-create-teams`                      | Whether members can create teams                                                    | No       |                         |\n| `members-can-delete-repositories`               | Whether members can delete repositories                                             | No       |                         |\n| `members-can-change-repo-visibility`            | Whether members can change repository visibility                                    | No       |                         |\n| `members-can-delete-issues`                     | Whether members can delete issues                                                   | No       |                         |\n| `default-repository-branch`                     | Default branch name for new repositories                                            | No       |                         |\n| `deploy-keys-enabled-for-repositories`          | Whether deploy keys can be added to repositories                                    | No       |                         |\n| `readers-can-create-discussions`                | Whether users with read access can create discussions                               | No       |                         |\n| `members-can-view-dependency-insights`          | Whether members can view dependency insights                                        | No       |                         |\n| `display-commenter-full-name-setting-enabled`   | Whether to display commenter full name in issues and PRs                            | No       |                         |\n| `rulesets-file`                                 | Comma-separated paths to JSON files, each with a single org ruleset config          | No       |                         |\n| `delete-unmanaged-rulesets`                     | Delete all other rulesets besides those being synced                                | No       | `false`                 |\n| `code-security-configurations-file`             | Path to a YAML file defining code security configurations to sync                   | No       |                         |\n| `delete-unmanaged-code-security-configurations` | Delete code security configurations not defined in the configuration file           | No       | `false`                 |\n| `dry-run`                                       | Preview changes without applying them                                               | No       | `false`                 |\n\n\u003e [!NOTE]\n\u003e You must provide either `organizations` or `organizations-file`. The `custom-properties-file`, `issue-types-file`, `rulesets-file`, and `code-security-configurations-file` inputs provide base settings for all orgs and can be combined with either approach. Member privilege settings can be provided as individual inputs (e.g., `default-repository-permission`). Per-org overrides in `organizations-file` layer on top of the base.\n\n## Syncing Actions Policy\n\nSync organization-level GitHub Actions security and policy settings across organizations. These control which actions can run, workflow token permissions, and PR approval policies.\n\nSet actions policy settings directly as action inputs:\n\n```yml\n- name: Sync Organization Settings\n  uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n  with:\n    github-token: ${{ secrets.ORG_ADMIN_TOKEN }}\n    organizations: 'my-org'\n    actions-policy-allowed-actions: selected\n    actions-policy-github-owned-allowed: true\n    actions-policy-verified-allowed: true\n    actions-allow-list-file: './actions-allow-list.yml'\n    actions-policy-default-workflow-permissions: read\n    actions-policy-actions-can-approve-pull-request-reviews: false\n```\n\n**Behavior:**\n\n- Only settings included in the config are managed — omitted settings remain unchanged\n- If a setting already matches the config, no API call is made\n- Settings are applied via `PUT` calls to the appropriate `/orgs/{org}/actions/permissions/*` endpoints\n- In dry-run mode, shows which settings would be changed without applying them\n- The `github-owned-allowed`, `verified-allowed`, and `actions-allow-list-file` settings only apply when `allowed-actions` is `selected`\n\n### Actions Policy Settings\n\n| Setting                                    | Type    | Description                                                                              |\n| ------------------------------------------ | ------- | ---------------------------------------------------------------------------------------- |\n| `allowed-actions`                          | string  | Allowed actions policy: `all`, `local_only`, or `selected`                               |\n| `github-owned-allowed`                     | boolean | Allow GitHub-owned actions (when `allowed-actions` is `selected`)                        |\n| `verified-allowed`                         | boolean | Allow GitHub Marketplace verified creator actions (when `allowed-actions` is `selected`) |\n| `default-workflow-permissions`             | string  | Default `GITHUB_TOKEN` permissions for workflows: `read` or `write`                      |\n| `actions-can-approve-pull-request-reviews` | boolean | Whether GitHub Actions can approve pull request reviews                                  |\n\n### Actions Allow List File\n\nWhen `allowed-actions` is `selected`, use `actions-allow-list-file` to specify allowed action/reusable workflow patterns:\n\n```yaml\n# actions-allow-list.yml\nactions:\n  - actions/checkout@*\n  - actions/setup-node@*\n  - actions/cache@*\n  - myorg/* # all actions from an owner\n```\n\n### Per-Org Actions Policy Overrides\n\nIn `orgs.yml`, use `actions-policy` to override specific settings for an org:\n\n```yaml\norgs:\n  - org: my-org\n    # inherits base actions policy action inputs\n\n  - org: my-other-org\n    actions-policy:\n      allowed-actions: all # override base\n    # actions-allow-list-file: './config/other-org-allow-list.yml' # override allow list\n```\n\n---\n\n## Action Inputs\n\n| Input                                                     | Description                                                                         | Required | Default                 |\n| --------------------------------------------------------- | ----------------------------------------------------------------------------------- | -------- | ----------------------- |\n| `github-token`                                            | GitHub token for API access (requires `admin:org` scope)                            | Yes      |                         |\n| `github-api-url`                                          | GitHub API URL (e.g., `https://api.github.com` or `https://ghes.domain.com/api/v3`) | No       | `${{ github.api_url }}` |\n| `organizations`                                           | Comma-separated list of organization names                                          | No       |                         |\n| `organizations-file`                                      | Path to YAML file containing organization settings configuration                    | No       |                         |\n| `custom-properties-file`                                  | Path to a YAML file defining custom property schemas                                | No       |                         |\n| `delete-unmanaged-properties`                             | Delete custom properties not defined in the configuration file                      | No       | `false`                 |\n| `issue-types-file`                                        | Path to a YAML file defining issue type definitions                                 | No       |                         |\n| `delete-unmanaged-issue-types`                            | Delete issue types not defined in the configuration file                            | No       | `false`                 |\n| `default-repository-permission`                           | Default permission for org members: `read`, `write`, `admin`, `none`                | No       |                         |\n| `members-can-create-repositories`                         | Whether members can create repositories                                             | No       |                         |\n| `members-can-create-public-repositories`                  | Whether members can create public repositories                                      | No       |                         |\n| `members-can-create-private-repositories`                 | Whether members can create private repositories                                     | No       |                         |\n| `members-can-create-internal-repositories`                | Whether members can create internal repositories (GHEC/GHES only)                   | No       |                         |\n| `members-can-fork-private-repositories`                   | Whether members can fork private repositories                                       | No       |                         |\n| `web-commit-signoff-required`                             | Whether web UI commits require signoff                                              | No       |                         |\n| `members-can-create-pages`                                | Whether members can create GitHub Pages sites                                       | No       |                         |\n| `members-can-create-public-pages`                         | Whether members can create public GitHub Pages sites                                | No       |                         |\n| `members-can-create-private-pages`                        | Whether members can create private GitHub Pages sites                               | No       |                         |\n| `members-can-invite-outside-collaborators`                | Whether members can invite outside collaborators                                    | No       |                         |\n| `members-can-create-teams`                                | Whether members can create teams                                                    | No       |                         |\n| `members-can-delete-repositories`                         | Whether members can delete repositories                                             | No       |                         |\n| `members-can-change-repo-visibility`                      | Whether members can change repository visibility                                    | No       |                         |\n| `members-can-delete-issues`                               | Whether members can delete issues                                                   | No       |                         |\n| `default-repository-branch`                               | Default branch name for new repositories                                            | No       |                         |\n| `deploy-keys-enabled-for-repositories`                    | Whether deploy keys can be added to repositories                                    | No       |                         |\n| `readers-can-create-discussions`                          | Whether users with read access can create discussions                               | No       |                         |\n| `members-can-view-dependency-insights`                    | Whether members can view dependency insights                                        | No       |                         |\n| `display-commenter-full-name-setting-enabled`             | Whether to display commenter full name in issues and PRs                            | No       |                         |\n| `rulesets-file`                                           | Comma-separated paths to JSON files, each with a single org ruleset config          | No       |                         |\n| `delete-unmanaged-rulesets`                               | Delete all other rulesets besides those being synced                                | No       | `false`                 |\n| `actions-policy-allowed-actions`                          | Allowed GitHub Actions policy: `all`, `local_only`, or `selected`                   | No       |                         |\n| `actions-policy-github-owned-allowed`                     | Whether GitHub-owned actions are allowed (when `allowed-actions` is `selected`)     | No       |                         |\n| `actions-policy-verified-allowed`                         | Whether verified creator actions are allowed (when `allowed-actions` is `selected`) | No       |                         |\n| `actions-allow-list-file`                                 | Path to YAML file with allowed action/reusable workflow patterns                    | No       |                         |\n| `actions-policy-default-workflow-permissions`             | Default `GITHUB_TOKEN` permissions for workflows: `read` or `write`                 | No       |                         |\n| `actions-policy-actions-can-approve-pull-request-reviews` | Whether GitHub Actions can approve pull request reviews                             | No       |                         |\n| `dry-run`                                                 | Preview changes without applying them                                               | No       | `false`                 |\n\n\u003e [!NOTE]\n\u003e You must provide either `organizations` or `organizations-file`. The `custom-properties-file`, `issue-types-file`, `rulesets-file`, and `actions-allow-list-file` inputs provide base settings for all orgs and can be combined with either approach. Member privilege settings can be provided as individual inputs (e.g., `default-repository-permission`). Actions policy settings can be provided as individual inputs (e.g., `actions-policy-allowed-actions`). Per-org overrides in `organizations-file` layer on top of the base.\n\n## Action Outputs\n\n| Output                    | Description                                                          |\n| ------------------------- | -------------------------------------------------------------------- |\n| `updated-organizations`   | Number of organizations successfully processed (changed + unchanged) |\n| `changed-organizations`   | Number of organizations with changes (or would have in dry-run mode) |\n| `unchanged-organizations` | Number of organizations with no changes                              |\n| `failed-organizations`    | Number of organizations that failed to update                        |\n| `warning-organizations`   | Number of organizations that emitted warnings                        |\n| `results`                 | JSON array of update results for each organization                   |\n\n## Dry-Run Mode\n\nUse `dry-run: true` to preview what changes would be made without actually applying them. The job summary will show all planned changes prefixed with \"Would\":\n\n```text\n🔍 DRY-RUN MODE: No changes will be applied\n  🆕 Would Create custom property: team\n  🆕 Would Create custom property: environment\n  📝 Would Update custom property: is-production (required: false → true)\n```\n\n## Development\n\n### Setup\n\n```bash\nnpm install\n```\n\n### Available Scripts\n\n```bash\nnpm test              # Run tests\nnpm run lint          # Check code quality with ESLint\nnpm run format:write  # Run Prettier for formatting\nnpm run package       # Bundle for distribution\nnpm run all           # Run format, lint, test, coverage, and package\n```\n\n### Testing Locally\n\n```bash\nenv 'INPUT_GITHUB-TOKEN=ghp_xxx' \\\n    'INPUT_ORGANIZATIONS=my-org' \\\n    'INPUT_CUSTOM-PROPERTIES-FILE=./sample-configuration/custom-properties.yml' \\\n    'INPUT_DRY-RUN=true' \\\n    node \"$(pwd)/src/index.js\"\n```\n\n## Working Example\n\nFor a complete working example of this action in use, see the [sync-github-org-settings](https://github.com/joshjohanning/sync-github-org-settings) repository:\n\n- **[orgs.yml](https://github.com/joshjohanning/sync-github-org-settings/blob/main/orgs.yml)** - Example configuration file with per-org overrides\n- **[sync-github-org-settings.yml](https://github.com/joshjohanning/sync-github-org-settings/blob/main/.github/workflows/sync-github-org-settings.yml)** - Example workflow using a GitHub App token\n\n**Example workflow:**\n\n```yml\nname: sync-github-org-settings\n\non:\n  push:\n    branches: ['main']\n  pull_request:\n    branches: ['main']\n  workflow_dispatch:\n\njobs:\n  sync-github-org-settings:\n    runs-on: ubuntu-latest\n    if: github.actor != 'dependabot[bot]'\n    permissions:\n      contents: read\n\n    steps:\n      - uses: actions/checkout@v6\n\n      - uses: actions/create-github-app-token@v3\n        id: app-token\n        with:\n          app-id: ${{ vars.APP_ID }}\n          private-key: ${{ secrets.APP_PRIVATE_KEY }}\n          owner: ${{ github.repository_owner }}\n\n      - name: Sync Organization Settings\n        uses: joshjohanning/bulk-github-org-settings-sync-action@v1\n        with:\n          github-token: ${{ steps.app-token.outputs.token }}\n          organizations-file: 'orgs.yml'\n          custom-properties-file: './config/custom-properties/base.yml'\n          dry-run: ${{ github.event_name == 'pull_request' }} # dry run if PR\n```\n\n## Important Notes\n\n- Settings not specified will remain unchanged\n- Custom properties and member privileges that already match the config are skipped (no unnecessary API calls)\n- Failed updates are logged as warnings but don't fail the action; if one or more organizations fail entirely, the action is marked as failed\n- With `delete-unmanaged-properties: true`, properties not in the config are **deleted** from the organization\n- `members-can-create-internal-repositories` only applies to organizations on GitHub Enterprise Cloud (GHEC) or GitHub Enterprise Server (GHES)\n\n## Contributing\n\nContributions are welcome! See the [Development](#development) section for setup instructions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshjohanning%2Fbulk-github-org-settings-sync-action","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoshjohanning%2Fbulk-github-org-settings-sync-action","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshjohanning%2Fbulk-github-org-settings-sync-action/lists"}