Managing repositories as resources

Added in version 1.1.0.

On Salt 3008.3 and later, this extension provides the github resource type, which exposes each GitHub repository as an individually targetable Salt resource. Compared to the classic github_repo modules, resources offer:

  • direct targeting of repositories (salt 'my-org/my-repo' / salt -C 'T@github:my-org/my-repo'), including grain-based targeting across all managed repositories (salt -G 'default_branch:master')

  • per-repository grains (owner, default branch, visibility, …) - a repository resource’s grains can optionally even include data files from the repo itself

  • repository-implicit execution and state modules – SLS files describe one repository’s desired configuration and are applied per resource, without threading repo_name/owner through every call

The classic modules remain fully supported (and are the only option on Salt 3006/3007); both are thin layers over the same core implementation.

Note

While the resource subsystem was introduced in Salt 3008.0, this extension requires 3008.3+: that release made the per-resource execution loader deny-by-default, so that jobs dispatched to a resource only see the modules this extension ships for it. On earlier 3008 releases, the loader was additive – stock and classic extension modules leaked into the resource context – which this extension’s modules are neither written nor tested for.

Setup

Declare the resource type in the managing minion’s pillar, under the subtree selected by the resource_pillar_key minion option (default: resources):

e.g. /etc/salt/minion.d/github_resource.yml
resources:
  github:
    profile: github
    owners:
      - my-org

All declaration keys – repository include/exclude patterns, archived handling and the profile, each overridable per owner (e.g. for repositories spanning credentials) – are described in the configuration guide. The referenced profiles are configured as usual (see the profile parameters).

After changing the declaration, refresh the minion’s resources:

salt 'minion' saltutil.refresh_resources

Each repository is registered as a resource named <owner>/<repo>, i.e. with the SRN github:<owner>/<repo>.

Targeting

# One repository, by ID
salt 'my-org/my-repo' test.ping

# One repository, by SRN
salt -C 'T@github:my-org/my-repo' test.ping

# By resource grain
salt -G 'default_branch:master' repo.info

The resource grains carry the repository’s identity and basic metadata: id, owner, repo, full_name, private, visibility, fork, archived, disabled, is_template, default_branch, language, license, topics, custom_properties, html_url, clone_url, ssh_url, description, homepage, created_at, has_discussions, has_pages and has_projects.

Custom grains sourced from files inside each repository can be declared via resource:grains_files, each namespace becoming a grain key next to the builtin ones (the special _ namespace merges into the root grains, never overwriting existing keys):

salt -G 'copier:template_version:2*' repo.info

Important

Custom grains are controlled by anyone who can commit to the respective repository. Restrict the exposed keys via include allowlists and keep that trust model in mind when building targeting expressions.

Hint

File-based grains and account metadata survive across processes (e.g. salt-call --local invocations) in a persistent cache, which is enabled by default (opt out per profile via cache). Cached file contents stay valid until the respective repository receives a new push.

Execution modules

Jobs dispatched to a github resource use repository-implicit, entity-scoped execution modules instead of the classic ones:

salt 'my-org/my-repo' repo.update description='Managed by Salt'
salt 'my-org/my-repo' actions.set_secret MY_SECRET hunter2
salt 'my-org/my-repo' deploy_key.list
salt 'my-org/my-repo' environment.get release

See the module reference for the complete list.

States

State runs dispatched to a resource converge that repository. A typical repo_setup.sls:

Repository settings are managed:
  repo.managed:
    - description: Managed by Salt
    - has_issues: true
    - teams:
        my-team: push

release:
  environment.present:
    - deployment_branches:
        - main
  label.present:
    - color: "#00FF00"

Autorelease deploy key is present:
  deploy_key.present:
    - name: autorelease
    - key: ssh-ed25519 AAAA...

Workflow permissions are restricted:
  actions.workflow_permissions_managed:
    - default_workflow_permissions: read
    - can_approve_pull_request_reviews: true
salt 'my-org/my-repo' state.apply repo_setup

Unlike the classic github_repo.present state, repo.present never creates the repository – a resource’s existence is a given. Repository creation (and deletion) remains a classic-module task on the managing minion:

salt 'minion' github_repo.create my-new-repo
salt 'minion' saltutil.refresh_resources