Git Product home page Git Product logo

secrets-sync-action's Introduction

Secrets Sync Action

Build Release codecov GitHub contributors semantic-release

A Github Action that can sync secrets from one repository to many others. This action allows a maintainer to define and rotate secrets in a single repository and have them synced to all other repositories in the Github organization or beyond. Secrets do not need to be sensitive and could also be specific build settings that would apply to all repositories and become available to all actions. Regex is used to select the secrets and the repositories. Exclude is currently not supported and it is recommended to use a bot user if possible.

Inputs

github_token

Required, Token to use to get repos and write secrets. ${{secrets.GITHUB_TOKEN}} will not work as it does not have the necessary scope for other repositories. This token should have the full "repo" scope. In older instances of GitHub, a fine-grained token may not support the required GraphQL API and a "Classic" personal access token would be required. As this is deprecated, please try a fine-grained token first.

repositories

Required, Newline delimited regex expressions to select repositories. Repositories are limited to those in which the token user is an owner or collaborator. Set repositories_list_regex to False to use a hardcoded list of repositories. Archived repositories will be ignored.

github_api_url

Override default GitHub API URL. When not provided, the action will attempt to use an environment variable provided by the GitHub Action runner environment defaults.

repositories_list_regex

If this value is true (default), the action will find all repositories available to the token user and filter based upon the regex provided. If it is false, it is expected that repositories will be a newline delimited list in the form of org/name.

secrets

Required, Newline delimited regex expressions to select values from process.env. Use the action env to pass secrets from the repository in which this action runs with the env attribute of the step.

retries

The number of retries to attempt when making Github calls when triggering rate limits or abuse limits. Defaults to 3.

concurrency

The number of allowed concurrent calls to the set secret endpoint. Lower this number to avoid abuse limits. Defaults to 10.

dry_run

Run everything except for secret create and update functionality.

delete

When set to true, the action will find and delete the selected secrets from repositories. Defaults to false.

environment

If this value is set to the name of a valid environment in the target repositories, the action will not set repository secrets but instead only set environment secrets for the specified environment. When not set, will set repository secrets only. Only works if target is set to actions (default).

target

Target where secrets should be stored: actions (default), codespaces or dependabot.

Usage

uses: jpoehnelt/secrets-sync-action@[insert version or commit]
  with:
    SECRETS: |
      ^FOO$
      ^GITHUB_.*
    REPOSITORIES: |
      ${{github.repository}}
    DRY_RUN: true
    GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN_CLASSIC }}
    GITHUB_API_URL: ${{ secrets.CUSTOM_GITHUB_API_URL }}
    CONCURRENCY: 10
  env:
    FOO: ${{github.run_id}}
    FOOBAR: BAZ

See the workflows in this repository for another example.

secrets-sync-action's People

Contributors

actions-user avatar arjunkhunti avatar clrung avatar davisodomhd avatar dependabot[bot] avatar devenes avatar erodewald avatar jpoehnelt avatar laugslander avatar natanande avatar plabick avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

secrets-sync-action's Issues

github_token - alternatives to secrets.GITHUB_TOKEN

The README says about github_token

{{secrets.GITHUB_TOKEN}} will not work.

But it's not clear what is supposed to work. Is this meant to be a github personal access token, or what other alternatives are there ?

Do I need to consider writing custom code as in Issue #9 ?

can't use regex in private org repo

Hi,

Thanks for making this! ๐Ÿ‘‹ The API seems to be straightforward. I'm trying to use regex in my private org, and it seems to be not finding it.

For example, if I have these repositories.

username/foo-bar
org/foo-bar
org/foo-baz

and I have these at my repositories

        REPOSITORIES: |
           username/foo.*
           org/foo.*

Only the username repo is found. Also, I do have access to those repositories, because if I use the full name, this action can find the private org repositories.

Usage of this action behind a corporate proxy

Hi,

we have a runner in our corporate network and we want to use this action to push secrets into our Github Enterprise (in the Internet). To reach our Github Enterprise server we need to go through a proxy. The proxy is configured in the environment variables "HTTPS_PROXY" as well "https_proxy", still we get an error that looks like no proxy is used.

Here is the log with debug enabled (removing all our secret names etc)

##[debug]Starting: Set up job
Current runner version: '2.286.1'
Runner name: '7342292feada'
Runner group name: 'Default'
Machine name: '7342292feada'
GITHUB_TOKEN Permissions
##[debug]Primary repository: XX/xxx-github-secret-sync
Runner is running behind proxy server 'http://172.17.0.1:3128/' for all HTTP requests.
Runner is running behind proxy server 'http://172.17.0.1:3128/' for all HTTPS requests.
Prepare workflow directory
##[debug]Update context data
##[debug]Evaluating job-level environment variables
##[debug]Evaluating job container
##[debug]Evaluating job service containers
##[debug]Evaluating job defaults
Prepare all required actions
Getting action download info
Download action repository 'hashicorp/[email protected]' (SHA:d5a69ceca1c3867700c32135c0da4788efdd2c0e)
##[debug]Download 'https://api.github.com/repos/hashicorp/vault-action/tarball/d5a69ceca1c3867700c32135c0da4788efdd2c0e' to '/home/docker/actions-runner/_work/_actions/_temp_4be30490-3054-48ca-9e49-71763f92292c/c66689af-de0a-4234-9608-ac91264f95e7.tar.gz'
##[debug]Unwrap 'hashicorp-vault-action-d5a69ce' to '/home/docker/actions-runner/_work/_actions/hashicorp/vault-action/v2.3.1'
##[debug]Archive '/home/docker/actions-runner/_work/_actions/_temp_4be30490-3054-48ca-9e49-71763f92292c/c66689af-de0a-4234-9608-ac91264f95e7.tar.gz' has been unzipped into '/home/docker/actions-runner/_work/_actions/hashicorp/vault-action/v2.3.1'.
Download action repository 'google/[email protected]' (SHA:e6f0df4615d7c34914b555f545cf63857001fef9)
##[debug]Download 'https://api.github.com/repos/google/secrets-sync-action/tarball/e6f0df4615d7c34914b555f545cf63857001fef9' to '/home/docker/actions-runner/_work/_actions/_temp_3c12f94f-ffef-4ac7-8127-958aeffa4a7c/3b37aff8-12aa-4040-bbc0-dd1b1eacb830.tar.gz'
##[debug]Unwrap 'google-secrets-sync-action-e6f0df4' to '/home/docker/actions-runner/_work/_actions/google/secrets-sync-action/v1.6.0'
##[debug]Archive '/home/docker/actions-runner/_work/_actions/_temp_3c12f94f-ffef-4ac7-8127-958aeffa4a7c/3b37aff8-12aa-4040-bbc0-dd1b1eacb830.tar.gz' has been unzipped into '/home/docker/actions-runner/_work/_actions/google/secrets-sync-action/v1.6.0'.
##[debug]action.yml for action: '/home/docker/actions-runner/_work/_actions/hashicorp/vault-action/v2.3.1/action.yml'.
##[debug]action.yml for action: '/home/docker/actions-runner/_work/_actions/google/secrets-sync-action/v1.6.0/action.yml'.
##[debug]Set step 'hashicorpvault-action' display name to: 'Import Secrets from Vault'
##[debug]Set step 'googlesecrets-sync-action' display name to: 'Sync quasar secrets'
##[debug]Collect running processes for tracking orphan processes.
##[debug]Finishing: Set up job

... (Pulling the secrets out of hashicorp vault)

Run google/[email protected]
  with:
    SECRETS: ^xxx
  ^xxx
 [...]
    REPOSITORIES: ^xx/xxxxxxxxx
  ^xx/xxxxxxxxx
  ^xx/xxxxxxxxx
  ^xx/xxxxxxxxx
  ^xx/xxxxxxxxx
  ^xx/xxxxxxxxx
  ^xx/xxxxxxxxx

    DRY_RUN: false
    GITHUB_TOKEN: ***
    CONCURRENCY: 1
    repositories_list_regex: true
    retries: 3
    delete: false
  env:
    [...]
    
Available env keys: ["SHLVL","HOME","REQUESTS_CA_BUNDLE","ORGANIZATION","HTTP_PROXY","DOTNET_SYSTEM_GLOBALIZATION_INVARIANT","requests_ca_bundle","HOSTNAME","http_proxy","PWD","https_proxy","ACTIONS_ALLOW_UNSECURE_COMMANDS","RUNNER_TRACKING_ID","GITHUB_ACTIONS","TOKEN","REPOSITORY","PATH","OLDPWD","_","HTTPS_PROXY","CI","RUNNER_LABELS","no_proxy","NO_PROXY",[... (secrets we pulled out of vault) ],"INPUT_SECRETS","INPUT_REPOSITORIES","INPUT_DRY_RUN","INPUT_GITHUB_TOKEN","INPUT_CONCURRENCY","INPUT_GITHUB_API_URL","INPUT_REPOSITORIES_LIST_REGEX","INPUT_RETRIES","INPUT_DELETE","GITHUB_JOB","GITHUB_REF","GITHUB_SHA","GITHUB_REPOSITORY","GITHUB_REPOSITORY_OWNER","GITHUB_RUN_ID","GITHUB_RUN_NUMBER","GITHUB_RETENTION_DAYS","GITHUB_ACTOR","GITHUB_WORKFLOW","GITHUB_HEAD_REF","GITHUB_BASE_REF","GITHUB_EVENT_NAME","GITHUB_SERVER_URL","GITHUB_API_URL","GITHUB_GRAPHQL_URL","GITHUB_WORKSPACE","GITHUB_ACTION","GITHUB_EVENT_PATH","GITHUB_ACTION_REPOSITORY","GITHUB_ACTION_REF","GITHUB_PATH","GITHUB_ENV","RUNNER_DEBUG","RUNNER_OS","RUNNER_ARCH","RUNNER_NAME","RUNNER_TOOL_CACHE","RUNNER_TEMP","RUNNER_WORKSPACE","ACTIONS_RUNTIME_URL","ACTIONS_RUNTIME_TOKEN"]
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
::add-mask::***
##[debug]Enhanced Annotations not enabled on the server. The 'title', 'end_line', and 'end_column' fields are unsupported.
Error: HttpError: request to https://github.xxxxxxxxx.com/api/v3/user/repos?affiliation=owner%2Ccollaborator%2Corganization_member&page=1&pageSize=30 failed, reason: getaddrinfo ENOTFOUND github.xxxxxxxxx.com
##[debug]Enhanced Annotations not enabled on the server. The 'title', 'end_line', and 'end_column' fields are unsupported.
Error: request to https://github.xxxxxxxxx.com/api/v3/user/repos?affiliation=owner%2Ccollaborator%2Corganization_member&page=1&pageSize=30 failed, reason: getaddrinfo ENOTFOUND github.xxxxxxxxx.com
##[debug]Node Action run completed with exit code 1
##[debug]Finishing: Sync xxxxxxxxx secrets

Organization change

Could you tell us why the organization has changed all of a sudden? It used to be google/secret-sync-action till July 12.

Abuse Detection Limits

Hi @jpoehnelt ๐Ÿ‘‹

I just want to report that I triggered an abuse detection mechanism for setting up secrets:

image

I have 128 113 (did a :%sort u) entries in my list, and I sync about 2 secrets per repo.

##[error]HttpError: Not Found

  
name: sync-secret

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Secrets Sync Action
      uses: google/[email protected]
      with:
        github_token:  ${{ secrets.SYNC_TOKEN }}
        repositories: ${{github.repository}}
        secrets: ^DEPLOY_*
        dry_run: true
      env:
        DEPLOY_SERVER_TEST_KEY: ${{ secrets.TEST_DEPLOY_KEY }}

this action throw a error

full output:

Run google/[email protected]
  with:
    github_token: *** 
    repositories: material-crm-server
    secrets: ^DEPLOY_*
    dry_run: true
  env:
    DEPLOY_SERVER_TEST_KEY: ***
[DRY_RUN='true'] No changes will be written to secrets
Available env keys: ["HOME","RUNNER_USER","USER","AZURE_EXTENSION_DIR","CI","JAVA_HOME_12_X64","JOURNAL_STREAM","LEIN_JAR","DOTNET_SKIP_FIRST_TIME_EXPERIENCE","ImageOS","ImageVersion","CONDA","JAVA_HOME","DEBIAN_FRONTEND","PERFLOG_LOCATION_SETTING","VCPKG_INSTALLATION_ROOT","LEIN_HOME","JAVA_HOME_11_X64","GOROOT_1_11_X64","GOROOT_1_14_X64","BOOST_ROOT_1_72_0","BOOST_ROOT_1_69_0","ANDROID_HOME","GOROOT","RUNNER_TOOL_CACHE","JAVA_HOME_7_X64","SELENIUM_JAR_PATH","CHROME_BIN","CHROMEWEBDRIVER","GECKOWEBDRIVER","RUNNER_PERFLOG","INVOCATION_ID","ANDROID_SDK_ROOT","DEPLOYMENT_BASEPATH","LANG","RUNNER_TRACKING_ID","GOROOT_1_13_X64","POWERSHELL_DISTRIBUTION_CHANNEL","PATH","GOROOT_1_12_X64","SWIFT_PATH","M2_HOME","ANT_HOME","JAVA_HOME_8_X64","GRADLE_HOME","GITHUB_ACTIONS","AGENT_TOOLSDIRECTORY","DEPLOY_SERVER_TEST_KEY","DEPLOY_SERVER_TEST1_HOST","DEPLOY_SERVER_TEST1_USER","INPUT_GITHUB_TOKEN","INPUT_REPOSITORIES","INPUT_SECRETS","INPUT_DRY_RUN","GITHUB_JOB","GITHUB_REF","GITHUB_SHA","GITHUB_REPOSITORY","GITHUB_REPOSITORY_OWNER","GITHUB_RUN_ID","GITHUB_RUN_NUMBER","GITHUB_ACTOR","GITHUB_WORKFLOW","GITHUB_HEAD_REF","GITHUB_BASE_REF","GITHUB_EVENT_NAME","GITHUB_WORKSPACE","GITHUB_ACTION","GITHUB_EVENT_PATH","RUNNER_OS","RUNNER_TEMP","RUNNER_WORKSPACE","ACTIONS_RUNTIME_URL","ACTIONS_RUNTIME_TOKEN","ACTIONS_CACHE_URL"]
Available repositories: ["huide-tech/action-test","huide-tech/deploy-secrets-sync","huide-tech/material-crm-react","huide-tech/material-crm-server","huide-tech/production-server"]
{
  "REPOSITORIES": [
    "huide-tech/deploy-secrets-sync"
  ],
  "SECRETS": [
    "^DEPLOY_+"
  ],
  "DRY_RUN": true,
  "FOUND_REPOS": [
    "huide-tech/deploy-secrets-sync"
  ],
  "FOUND_SECRETS": [
    "DEPLOY_SERVER_TEST_KEY"
  ]
}
##[error]HttpError: Not Found
##[error]Not Found

Documentation README.md should fix a sample value for GITHUB_TOKEN

Problem

The Usage example in README.md file has GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN_SECRETS }}. However, GITHUB_ prefix is reserved for GitHub context and, thus, that should not work.

Proposed solution

Update the Usage example to change the sample value of GITHUB_TOKEN to something like CUSTOM_TOKEN_SECRETS

feature: sync secrets to Azure DevOps instances

Hi, I have a feature suggestion:
I'd love to use this action to sync not only our GitHub Enterprise projects, but also to variable groups in Azure DevOps instances (both Server and Service/Cloud). There is a REST API to update variable groups, but I haven't tested it yet. Have you thought about this already? Here are my thoughts:

  1. GitHub secrets would need to be mapped to variables in variable groups in some way, maybe you'd run the action once for every variable group to sync into: give both the DevOps Organisation URL and variable group ID as inputs, the GITHUB_TOKEN would have to be a DevOps token of course, maybe refactor its name to "ACCESS_TOKEN" ๐Ÿ˜‰. This "one action for each variable group" idea makes extra sense considering each group may have a different maintainer, so a different access token may be required for some groups.

  2. I'm worried that the REST API may not allow to sync single secrets and it will simply delete any variables that aren't in the payload (there doesn't seem to be any other way to delete variables via REST).
    If so, we have to mention this as a big warning in the readme, potentially we could introduce a safeguard: Before actually synching, get the current content of the group and check it against what we are about to send. Abort with error message if there are variables we aren't going to set. Possibly allow to disable this check with an "allowDeletingExisting: true" input variable or something...
    We could read the value of non-secret variables and simply reset them to the existing value, so we would only need to fail if there are secrets we can't update (you don't get their value via REST), but special treatment like this makes the whole thing more complicated and edge cases hard to understand, so better to keep it simple.

  3. People would want to specify the "group name" as input instead of "group ID", we can use a REST endpoint to get the group ID from the name, I think we should do this for the user.

  4. DevOps has the concept of descriptions for variable groups. My hope is that if we don't specify one in the UPDATE call, it will just keep the existing description. If this turns out not to be the case, we could require this as input to the action, potentially defaulting to "synchronized from GitHub repository https://..." and just overwriting any changes anyone may have done to the description in DevOps.
    As with the variables we could of course first check that nobody has modified it and fail if that's the case. It looks more and more like we will want to consider synced variable groups to be read-only on DevOps side and nobody should modify any aspect of them.

  5. Variable Groups have a couple other settings as well, like access permissions and whether it's automatically accessible from every pipeline... I'm not sure we should create variable groups that don't exist. If we did, we would have to mirror all these settings in inputs for the action.
    Instead I suggest to require someone to manually set up the empty variable group to ensure they've set everything up correctly, and this action only updates existing groups. Encountering a non-existent group would be treated as error.

  6. DevOps has the concept of non-secret variables that are automatically available to actions as environment variables, but I think we should ignore this and actively set everything we sync to "isSecret".
    Otherwise we would have to specify for each variable whether it should be a secret or not... Or can you easily set this on the patterns, like this?

    - secrets:
      - pattern: "^FOO_"
      - pattern: "^BAR_"
        isSecret: false # default is true

    This will require some refactoring of the secrets input, but I believe we can keep the old syntax working in parallel to the proposed one (I've seen the same handled elsewhere, I myself have no idea how yaml parsing works ๐Ÿ˜œ)
    Otherwise have some naming convention like "if the secret name starts with 'NONSECRET_', remove this prefix from the variable name to be synched and set 'isSecret: false'". But I don't like to do stuff like that. Whatever the case, this is an optional feature and the initial implementation shouldn't support this at all to keep it simple ๐Ÿ˜‰

Please let me know what you think.

Issue with "secrets-sync-action" in internal repositories

Previously, we utilized the "secrets-sync-action" to synchronize secrets between repositories. Up until July 12th, the action was registered as "google/secret-sync-action." After that date, the organization was changed to "jpoehnelt/secret-sync-action."

Unfortunately, our workflow is currently nonfunctional, as the action can no longer be employed in our repository. It appears that our organization has imposed restrictions on the actions that can be invoked from workflows.

Has anyone managed to solve this issue?

Updating Description

It would be very attractive if we can add some more photos and GIF's related to Bot!

source

Google

uses: google/secrets-sync-action
with:
SECRETS: |
^FOO$
^GITHUB_.*
REPOSITORIES: |
${{github.repository}}
DRY_RUN: true
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN_SECRETS }}
CONCURRENCY: 10
env:
FOO: ${{github.run_id}}
FOOBAR: BAZ

Sync secrets to all a team's repos

It would be helpful to sync secrets to all repos managed by a team. The regex match is good but doesn't cover all edge cases. If this is a feature that is approved, I would like to implement it.

Sync secrets into repository Environments

Github repositories has a neat feature where one can specify a set of environments with their own protection rules.
https://docs.github.com/en/actions/reference/environments#environment-secrets

This is useful for reusing and writing clean workflow code. For example, I might have a secret DEPLOY_TOKEN in my environment "prod", and the same secret with different value in "dev". This allows an action to simply deploy using the same secret name all the time, and the set environment decides the value (and if it's allowed to be used).

This becomes especially important when the number of environments grows. With environment secrets, the workflow code stays the same, but without, the code has to be modified and grown each time a new environment is added.

GITHUB_TOKEN generated from GitHub App Jwt could not be used.

Hi, thanks for making this!

Concept is clear and it work very well on my private account.

Summary

Is there any plan to allow using GitHub App's generated token for GITHUB_TOKEN?

Description

I've tried to use Organization's GitHub App to generate GitHub Token, which is non-user related token and organization easily control app's permission and integration. However I met following error when trying to use this token.

Resource not accessible by integration

Reproduce

  • Generate GitHub App on Org, set permission Secrets and Actions read-write, then install it.
  • Generate Private Key YOUR_GITHUB_APP.YYYY-MM-DD.private-key.pem for the GitHub App and download it.
  • Get ClientId and InstallationId.
  • Run following to generate GitHub App's Token and show on console.
let jwt = require("jsonwebtoken")
let fs = require("fs")
let axios = require("axios")

let payload = {
    exp: Math.floor(Date.now() / 1000) + 600,  // JWT expiration time max 10min
    iat: Math.floor(Date.now() / 1000) - 10,  // Issued at time 
    iss: "<CLIENT_ID>"
}
let cert = fs.readFileSync("YOUR_GITHUB_APP.2020-04-26.private-key.pem").toString()
let jwtToken = jwt.sign(payload, cert, { algorithm: 'RS256' });
console.log(jwtToken);

axios.default.post("https://api.github.com/installations/<INSTALLATION_ID>/access_tokens", null, {
    headers: {
        Authorization: "Bearer " + jwtToken,
        Accept: "application/vnd.github.machine-man-preview+json"
    }
})
.then(res => console.log(res.data.token)) // this is the GitHub App's Token
.catch(console.log)
  • Set GitHub Token to secrets as GITHUB_APP_TOKEN and try run secrets-sync-action.
name: Sync
on:
  push:
    branches:
      - master

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: google/[email protected]
        with:
          SECRETS: |
            ^SYNC_
          REPOSITORIES: |
            ^FOO
          GITHUB_TOKEN: ${{ env.GITHUB_APP_TOKEN }}
          DRY_RUN: true
        env:
          SYNC_TEST: ${{ secrets.TEST }}

You may got following error.

Run google/[email protected]

##[error]HttpError: Resource not accessible by integration
##[error]Resource not accessible by integration

Reason

This seems due to await octokit.repos.listForAuthenticatedUser API using at github.ts

It is useful API and works great for User Token.

https://octokit.github.io/rest.js/v17#repos-list-for-authenticated-user

However Github App's integrated token is not supporting this API.

https://developer.github.com/v3/apps/available-endpoints/#repositories

Specify that new fine-grained tokens cannot be used for private repos

It took me quite a while to discover what was causing only public repos to show despite granting access to private repos on the fine-grained token.

Fine-grained tokens are new, but are encouraged as they are much better for least-privilege.

However, as per the documentation, "Support for GraphQL. Currently, fine-grained PATs can only be used against the REST APIs". This may change in the futre.

If you run the following you get an error.

gh repo list --visibility private
HTTP 401: Personal access tokens with fine grained access do not support the GraphQL API (https://api.github.com/graphql)

Therefore, the documentation should specify that the GITHUB_TOKEN must be "Classic" not "Fine-grained" if you wish to push secrets to private repos.

How to sync environment and repository secrets that have the same name?

I have a secret1 which is defined as both environment and repository secret. When I sync the secret, it updates the repository secret as environment secret whereas I wanted to update the environment secret as environment secret. Is syncing of secret with the same name supported?

Also, how can we update multiple environments?

docs: no classic token needed anymore

The readme says about the github_token input A "Classic" personal access token is required. The "Fine-grained" tokens cannot be used as they do not support the GraphQL API at this time.
I've noticed that I cannot generate classic tokens on our Enterprise 3.7 instance, so I tried a scoped token, and it worked fine with the full "repo" scope.

I suspect the required permissions have been added to this scope at some point, so should the readme be updated? Or does this only apply in specific circumstances? Do we know which GHES version this applies to and in which a fine-grained token works?
Maybe it should cover all bases and state something like This token should have the full "repo" scope. In older instances of GitHub, a fine-grained token may not support the required GraphQL API and a "Classic" personal access token would be required. As this is deprecated, please try a fine-grained token first.

Main try/catch code never report error

Hi,
I am trying to use this github action. It looks very interesting to me. Great job by the way.

I have ran into an issue trying to make it work. I think I have some bad github token configuration and the job is likely failing.

I have activating the github action debugging but the only info I see is the following:
##[debug]Loading env Run google/[email protected] Available env keys: ["VCPKG_INSTALLATION_ROOT","GITHUB_ACTIONS","CONDA","GOROOT_1_12_X64","GRADLE_HOME","USER","GOROOT_1_14_X64","INVOCATION_ID","BOOST_ROOT_1_72_0","DEPLOYMENT_BASEPATH","DEBIAN_FRONTEND","PERFLOG_LOCATION_SETTING","BOOST_ROOT_1_69_0","JOURNAL_STREAM","HOME","ANDROID_HOME","AGENT_TOOLSDIRECTORY","GOROOT_1_11_X64","ImageVersion","JAVA_HOME_12_X64","GOROOT","LEIN_HOME","PATH","M2_HOME","ImageOS","DOTNET_SKIP_FIRST_TIME_EXPERIENCE","ANDROID_SDK_ROOT","JAVA_HOME","JAVA_HOME_8_X64","LANG","JAVA_HOME_11_X64","JAVA_HOME_7_X64","CHROME_BIN","LEIN_JAR","GECKOWEBDRIVER","ANT_HOME","SELENIUM_JAR_PATH","AZURE_EXTENSION_DIR","RUNNER_TOOL_CACHE","POWERSHELL_DISTRIBUTION_CHANNEL","GOROOT_1_13_X64","RUNNER_USER","RUNNER_TRACKING_ID","CHROMEWEBDRIVER","RUNNER_PERFLOG","DOCKER_USERNAME","INPUT_SECRETS","INPUT_REPOSITORIES","INPUT_DRY_RUN","INPUT_GITHUB_TOKEN","GITHUB_REF","GITHUB_SHA","GITHUB_REPOSITORY","GITHUB_RUN_ID","GITHUB_RUN_NUMBER","GITHUB_ACTOR","GITHUB_WORKFLOW","GITHUB_HEAD_REF","GITHUB_BASE_REF","GITHUB_EVENT_NAME","GITHUB_WORKSPACE","GITHUB_ACTION","GITHUB_EVENT_PATH","RUNNER_DEBUG","RUNNER_OS","RUNNER_TEMP","RUNNER_WORKSPACE","ACTIONS_RUNTIME_URL","ACTIONS_RUNTIME_TOKEN","ACTIONS_CACHE_URL"] ::add-mask::*** ##[debug]Node Action run completed with exit code 0 ##[debug]Finishing: Sync secrets

After digging in the source code I have found that in the main try/catch we have an anonymous function that got never called, so it seems to me that the job never show the error in the log, and it is never marked as failed.
https://github.com/google/secrets-sync-action/blob/2b3ca20a1944f6e1f9559015e3e0c92c61199873/src/main.ts#L81

Is this behavior on purpose?

Thank you so much.

Best Regards.

Allow specification of private/public repositories only

It would be helpful to have an option to specify whether to only include private repositories in the regex matching or only public / both as default. That way you could for example match a whole organization with the regex but specify to only sync tokens to private repositories of that organizations as those secrets would need to be kept in private repositories.

exclude search from archived repos

Hi @jpoehnelt ๐Ÿ‘‹

So this I was playing around with regex and I noticed, that the secret actually syncs archived repositories.
image

I'm not sure if it's a bug in Github, but archived repositories are supposed to be read-only. I think they just haven't added a guard for that yet.

So I'm not really sure if this is supposed to be another CLI option where you remove archived repositories in the search list via archived:false or should it be excluded by default.

Thoughts? Not sure if this is a bugfix or a feature?

PS. I accidentally hit submit, I'm not finished writing. ๐Ÿคฃ

Auto Remove Existing SECRETS and add only the new

I recently started using this action to my certain SECRETS available to repos.

but then i found out that this action does not remove Existing SECRETS

Let me give you an example

I have configured my workflow like below

      - name: "๐Ÿ”„ Sync Twitter Logins"
        uses: google/[email protected]
        with:
          repositories_list_regex: false
          SECRETS: |
            ^TWITTER_
          REPOSITORIES: ${{ env.TWITTER_LOGINS_REPOS }}
          DRY_RUN: ${{ env.DRY_RUN }}
          CONCURRENCY: ${{ env.CONCURRENCY }}
          GITHUB_TOKEN: ${{ secrets.GH_PUBLIC_PRIVATE_TOKEN }}

and i have below EVN's configured

env:
  DRY_RUN: false
  CONCURRENCY: 50
  TWITTER_API_KEY: ${{ secrets.TWITTER_API_KEY }}
  TWITTER_API_SECRET_KEY: ${{ secrets.TWITTER_API_SECRET_KEY }}
  TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
  TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
  TWITTER_LOGINS_REPOS: |
    varunsridharan/****
    varunsridharan/****
    varunsridharan/****
    varunsridharan/****
    varunsridharan/****

And when i ran the action to syn ll the SECRETS it also added TWITTER_LOGINS_REPOS to the repo

https://s2.do-spaces.com/2020/Jun/29/1593409947-114.jpg

I know its my mistake i should have configured the Regex Properly ..

but i would be great if this action and force remove all the matching SECRETS and add only the new matched SECRETS !

[Discussion] Ideas for v2

๐Ÿ‘‹ Hello @jpoehnelt ! It's me, the person who wanted to contribute some ideas that I had experimented on my own back to this repo (since it's the most popular). Here's some ideas for a @v2 release. These are some pretty drastic changes, and are very focused on improving the usability of this action and making it conform with existing conventions.

Here's a general overview of what I'd like to change. I know this is a lot but hear me out. I'll try to provide a rationale for each change:

  1. Use Deno or https://github.com/JasonEtco/build-and-tag-action. This gets rid of the pesky dist/ folder in source control which is a bit complex to make sure is in sync with code changes. Heck, if it's simple enough, you could even use Bash! (remember Bash is also on Windows runners via git bash) or even Python if you want! The key I think is to scale complexity of managing the project with the complexity of the code in the project. In this case, npm + dist folder is a bunch of extra stuff
  2. Use kebab-case inputs since this is what all the official actions use https://github.com/actions. It's also what most other user-made actions use and appears to be "the convention"
  3. Add aliases for repository repositories and other plurals. This greatly reduces the potential for typos and user frustration.
  4. Use GitHub Search syntax instead of regex to match multiple repos dynamically. This is more familiar to github users and very easy to test which repos it will apply to! Just use https://github.com/search!
  5. Remove (some) linting (config). This is more of a "this is excessive" opinion, but I think that in particular all the eslint and such could be replaced with deno lint or npx xo or something. Even then, there's enough safety with tsc that I don't think this project has reached "big status" to need such fancy linting stuff.
  6. Use more practical e2e tests instead of unit tests. Sure, ts tests are ok, but they don't compare to uses: ./ to actually run your action in CI. I find that a dry-run: flag plus a "real world" test or two works pretty good.
  7. Add a comparison blurb to the readme (after everything is said and done) about how this project compares to other secrets sync actions https://github.com/marketplace?type=actions&query=secrets+sync+
  8. Improve the "feel" of the readme. See https://github.com/Andrew-Chen-Wang/github-wiki-action for what I consider to be "good feel"
  9. Use explicit secrets instead of regex secrets. Sure, it's a tad harder to say "all secrets", but it really really helps for keeping which secrets sync where very explicit. And given that you're usually syncing only 1-5 secrets, this isn't much of a hassle that regex confusion is worth it imo.
  10. Use https://github.com/actions/publish-action to atuo-create v2 major tags from a release like v2.0.0
  11. Also support https://docs.github.com/en/actions/learn-github-actions/variables

You can kinda see my influence on this action that I've helped out with before: https://github.com/Andrew-Chen-Wang/github-wiki-action ๐Ÿ‘ˆ deliberately low tooling, as simple as possible.

Here's some ideas for interfaces of what I think could be cool:

This uses the mode: input to reuse the secrets and vars inputs for either set/delete operations

- uses: jpoehnelt/secrets-sync-action@v2
  with:
    token: ${{ secrets.MY_SECRETS_TOKEN }}
    repositories: |
      octocat/awesome-project
      octocat/my-library
      octocat/hello-world
    mode: set
    secrets: |
      NPM_TOKEN=${{ secrets.NPM_TOKEN }}
      VERCEL_TOKEN=${{ secrets.VERCEL_TOKEN }}
    vars: |
      NODE_VERSION=${{ vars.NODE_VERSION }}
      MESSAGE=hello
- uses: jpoehnelt/secrets-sync-action@v2
  with:
    token: ${{ secrets.MY_SECRETS_TOKEN }}
    repositories: |
      octocat/awesome-project
      octocat/my-library
      octocat/hello-world
    mode: delete
    secrets: |
      NPM_TOKEN=${{ secrets.NPM_TOKEN }}
      VERCEL_TOKEN=${{ secrets.VERCEL_TOKEN }}
    vars: |
      NODE_VERSION=${{ vars.NODE_VERSION }}
      MESSAGE=hello

As an alternative, you could make each one a separate input to be more explicit:

- uses: jpoehnelt/secrets-sync-action@v2
  with:
    token: ${{ secrets.MY_SECRETS_TOKEN }}
    repositories: |
      octocat/awesome-project
      octocat/my-library
      octocat/hello-world
    set-secrets: |
      NPM_TOKEN=${{ secrets.NPM_TOKEN }}
      VERCEL_TOKEN=${{ secrets.VERCEL_TOKEN }}
    set-variables: |
      NODE_VERSION=${{ vars.NODE_VERSION }}
      MESSAGE=hello
- uses: jpoehnelt/secrets-sync-action@v2
  with:
    token: ${{ secrets.MY_SECRETS_TOKEN }}
    repositories: |
      octocat/awesome-project
      octocat/my-library
      octocat/hello-world
    delete-secrets: |
      NPM_TOKEN
      VERCEL_TOKEN
    delete-variables: |
      NODE_VERSION
      MESSAGE

Or the action could support both! Both is good, just at the cost of code complexity.

Here's an idea for setting org-level secrets https://docs.github.com/en/codespaces/managing-codespaces-for-your-organization/managing-encrypted-secrets-for-your-repository-and-organization-for-github-codespaces#adding-secrets-for-an-organization

- uses: jpoehnelt/secrets-sync-action@v2
  with:
    token: ${{ secrets.USER_SECRETS_TOKEN }}
    organization: octocat
    vsibility: selected
    repositories: |
      octocat/our-lib
      octocat/awesome-app
    secrets-app: dependabot
    set-secrets: |
      NPM_TOKEN=${{ secrets.NPM_TOKEN }}
Here's how the Deno idea would work (I've used it before)

The idea is that you write your code in TypeScript and then you normally run it with ./cli.ts. But the problem is you need Deno. So guess what? Deno is a single binary that gets downloaded from GitHub Releases. It's really fast and easy to just get the ./deno binary. So what do you do? You spend ~1s downloading it and then you use that binary. This has the bonus side effect of putting you in control of the exact Deno version.

Let me remind you though, that this is an idea. An alternative is to use https://github.com/JasonEtco/build-and-tag-action

Reminder: Bash is available on windows too via git bash. Just use shell: bash.

runs:
  using: composite
  steps:
    - run: '"${GITHUB_ACTION_PATH%/}/cliw"'
      shell: bash
      env:
        INPUT_TOKEN: ${{ inputs.token }}
        INPUT_GITHUB_SERVER_URL: ${{ inputs.github-server-url }}
        INPUT_...: ...

โ˜ You can also use INPUTS_JSON: ${{ toJSON(inputs) }} if you're feeling concise ๐Ÿ˜Ž

#!/bin/sh
# Based on https://github.com/jcbhmr/deno_wrapper
set -e
# https://stackoverflow.com/a/29835459
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)
deno_dir="$script_dir/.deno"

# https://manpages.ubuntu.com/manpages/kinetic/en/man1/chronic.1.html
chronic() (
  set +e
  output=$($@ 2>&1)
  exit_code=$?
  set -e
  if [ "$exit_code" -ne 0 ]; then
    echo "$output" >&2
  fi
  return "$exit_code"
)

if [ ! -d "$deno_dir" ]; then
  # https://github.com/denoland/deno_install#readme
  export DENO_INSTALL=$deno_dir
  curl -fsSL https://deno.land/x/install/install.sh | chronic sh -s "v1.33.4"
fi

# https://github.com/denoland/deno_install/blob/master/install.sh#L53
export DENO_INSTALL=$deno_dir
export PATH="$DENO_INSTALL/bin:$PATH"

"$script_dir/cli.ts" "$@"
#!/usr/bin/env -S deno run -Aq
import process from "node:process";
import { readFile, writeFile } from "node:fs/promises";
import assert from "node:assert";
import * as core from "npm:@actions/core@^1.10.0";
import { $ } from "npm:zx@^7.2.2";
Here's what a Python script might look like

This script is nowhere near complete and just scratches the surface. Don't take as end-all-be-all, but instead as a demo that you can do GitHub actions stuff without a massive npm project and without a dist folder in source

Reminder: gh is available on windows, macos, and ubuntu runners! It's a great cross-platform way to interact with github for Bash scripts or other non-lib stuff.

#!/usr/bin/env python3
import subprocess
import os
import tempfile

input_repositories = os.getenv("INPUT_REPOSITORIES")
input_repository = os.getenv("INPUT_REPOSITORY")
input_query = os.getenv("INPUT_QUERY")
input_limit = os.getenv("INPUT_LIMIT")
input_token = os.getenv("INPUT_TOKEN")
input_github_server_url = os.getenv("INPUT_GITHUB_SERVER_URL")
input_dry_run = os.getenv("INPUT_DRY_RUN")
input_app = os.getenv("INPUT_APP")
input_secrets = os.getenv("INPUT_SECRETS")
input_secret = os.getenv("INPUT_SECRET")
input_variables = os.getenv("INPUT_VARIABLES")
input_variable = os.getenv("INPUT_VARIABLE")

assert(input_repositories ^ input_repository ^ input_query)
if query:
  cmd = ["gh", "search", "-L", input_limit, input_query, "--json", "fullName", "-q", ".[].fullName"]
  repositories = subprocess.check_output(cmd).decode("utf-8").splitlines()
else:
  repositories = (input_repositories or input_repository).splitlines()

env_text = (input_secrets or input_secret)
env_file = tempfile.NamedTemporaryFile(mode="w+t")
env_file.write(env_text)

dry_run = input_dry_run == "true"

for r in repositories:
  cmd = ["gh", "secret", "set", "-R", r, "-a", input_app, "-f", env_file.name]
  if dry_run:
    print(" ".join(cmd))
  else:
    subprocess.check_call(cmd)

env_text = (input_variables or input_variable)
env_file.seek(0)
env_file.write(env_text)

for r in repositories:
  cmd = ["gh", "variable", "set", "-R", r, "-f", env_file.name]
  if dry_run:
    print(" ".join(cmd))
  else:
    subprocess.check_call(cmd)

env_file.close()

No auditability

When using this Action, there is no auditability on who updated which secrets in which repository.

Open to contributions?

Hello! ๐Ÿ‘‹

I recently created this action https://github.com/jcbhmr/set-secrets-action due to some differences in usecases. I wanted to synchronize a few well-chosen secrets across numerous repositories sorta like how you can do org-level secrets. I wanted that but for users (doesn't exist natively on GitHub ๐Ÿ˜ญ). It appears that this action seems to go for a more wide-net approach with regex-based secret passing? ๐Ÿคทโ€โ™‚๏ธ

I'd be interested in merging some of my ideas/changes into this repository. But, it doesn't really seem like there's a lot of activity here. I'm worried that any PR I open will be stuck in limbo ๐Ÿคฃ

In particular:

  • Improve the readme. I've found that a - **`input`:** description of input list (with TWO spaces between each item) works pretty good for documenting inputs. <h2> is a bit too large, <table> is a bit too small. Ex: https://github.com/Andrew-Chen-Wang/github-wiki-action#inputs or https://github.com/jcbhmr/set-secrets-action#inputs. I'd also like to add some more examples.
  • Support a query: input? This could be a useful tool for those who prefer implicit secrets instead of explicit. ๐Ÿคทโ€โ™‚๏ธ
  • Allow repository and repositories
  • Allow secrerts and secret
  • Allow setting different app secrets #51

Action takes a very long time to execute with no status when an user has access to hundreds of repositories

Problem Statement

When running this GitHub Action script, it took me more than 15 minutes to execute. See below image.

image

This is because I have access to hundreds of repositories, and action tries to grab all repositories I have access to, not necessarily one authenticated through GitHub PAT token.

https://github.com/google/secrets-sync-action/blob/master/src/github.ts#L82

And there is no log or status that gets printed out when this execution is happening.

Proposed Solution

Give an option to filter out repositories to grab from where default option should be set to only authenticated one through SSO.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.