GitHub - Create Repo Secret

Octopus.Script exported 2023-10-19 by mcasperson belongs to ‘GitHub’ category.

This step creates a secret in a GitHub repo.

Parameters

When steps based on the template are included in a project’s deployment process, the parameters below can be set.

Secret Name

CreateGitHubSecret.GitHub.Secret.Name =

The name of the GitHub secret.

Secret Value

CreateGitHubSecret.GitHub.Secret.Value =

The secret value.

GitHub Repo Name

CreateGitHubSecret.Git.Url.Repo =

The GitHub repo name i.e. myrepo in the URLhttps://github.com/owner/myrepo.

Github Owner

CreateGitHubSecret.Git.Url.Organization =

The GitHub repo owner or organization i.e. owner in the URL https://github.com/owner/myrepo.

GitHub Access Token

CreateGitHubSecret.Git.Credentials.Password =

The GitHub access token

Script body

Steps based on this template will execute the following Python script.

# https://gist.github.com/comdotlinux/9a53bb00767a16d6646464c4b8249094

# This script forks a GitHub repo. It creates a token from a GitHub App installation to avoid
# having to use a regular user account.
import subprocess
import sys

# Install our own dependencies
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'jwt', '--disable-pip-version-check'])
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'pynacl', '--disable-pip-version-check'])

import requests
import json
import sys
import os
import urllib.request
import base64
import re
import jwt
import time
import argparse
import urllib3
from base64 import b64encode
from typing import TypedDict
from nacl import public, encoding

# Disable insecure http request warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# If this script is not being run as part of an Octopus step, setting variables is a noop
if 'set_octopusvariable' not in globals():
    def set_octopusvariable(variable, value):
        pass

# If this script is not being run as part of an Octopus step, return variables from environment variables.
# Periods are replaced with underscores, and the variable name is converted to uppercase
if "get_octopusvariable" not in globals():
    def get_octopusvariable(variable):
        return os.environ[re.sub('\\.', '_', variable.upper())]

# If this script is not being run as part of an Octopus step, print directly to std out.
if 'printverbose' not in globals():
    def printverbose(msg):
        print(msg)


def printverbose_noansi(output):
    """
    Strip ANSI color codes and print the output as verbose
    :param output: The output to print
    """
    output_no_ansi = re.sub(r'\x1b\[[0-9;]*m', '', output)
    printverbose(output_no_ansi)


def get_octopusvariable_quiet(variable):
    """
    Gets an octopus variable, or an empty string if it does not exist.
    :param variable: The variable name
    :return: The variable value, or an empty string if the variable does not exist
    """
    try:
        return get_octopusvariable(variable)
    except:
        return ''


def init_argparse():
    parser = argparse.ArgumentParser(
        usage='%(prog)s [OPTION]',
        description='Fork a GitHub repo'
    )

    parser.add_argument('--secret-name', action='store',
                        default=get_octopusvariable_quiet(
                            'CreateGitHubSecret.GitHub.Secret.Name') or get_octopusvariable_quiet(
                            'GitHub.Secret.Name'))
    parser.add_argument('--secret-value', action='store',
                        default=get_octopusvariable_quiet(
                            'CreateGitHubSecret.GitHub.Secret.Value') or get_octopusvariable_quiet(
                            'GitHub.Secret.Value'))

    parser.add_argument('--repo', action='store',
                        default=get_octopusvariable_quiet(
                            'CreateGitHubSecret.Git.Url.Repo') or get_octopusvariable_quiet(
                            'Git.Url.Repo') or get_octopusvariable_quiet('Octopus.Project.Name'))
    parser.add_argument('--git-organization', action='store',
                        default=get_octopusvariable_quiet(
                            'CreateGitHubSecret.Git.Url.Organization') or get_octopusvariable_quiet(
                            'Git.Url.Organization'))
    parser.add_argument('--github-app-id', action='store',
                        default=get_octopusvariable_quiet(
                            'CreateGitHubSecret.GitHub.App.Id') or get_octopusvariable_quiet('GitHub.App.Id'))
    parser.add_argument('--github-app-installation-id', action='store',
                        default=get_octopusvariable_quiet(
                            'CreateGitHubSecret.GitHub.App.InstallationId') or get_octopusvariable_quiet(
                            'GitHub.App.InstallationId'))
    parser.add_argument('--github-app-private-key', action='store',
                        default=get_octopusvariable_quiet(
                            'CreateGitHubSecret.GitHub.App.PrivateKey') or get_octopusvariable_quiet(
                            'GitHub.App.PrivateKey'))
    parser.add_argument('--git-password', action='store',
                        default=get_octopusvariable_quiet(
                            'CreateGitHubSecret.Git.Credentials.Password') or get_octopusvariable_quiet(
                            'Git.Credentials.Password'),
                        help='The git password. This takes precedence over the --github-app-id,  --github-app-installation-id, and --github-app-private-key')

    return parser.parse_known_args()


def generate_github_token(github_app_id, github_app_private_key, github_app_installation_id):
    # Generate the tokens used by git and the GitHub API
    app_id = github_app_id
    signing_key = jwt.jwk_from_pem(github_app_private_key.encode('utf-8'))

    payload = {
        # Issued at time
        'iat': int(time.time()),
        # JWT expiration time (10 minutes maximum)
        'exp': int(time.time()) + 600,
        # GitHub App's identifier
        'iss': app_id
    }

    # Create JWT
    jwt_instance = jwt.JWT()
    encoded_jwt = jwt_instance.encode(payload, signing_key, alg='RS256')

    # Create access token
    url = 'https://api.github.com/app/installations/' + github_app_installation_id + '/access_tokens'
    headers = {
        'Authorization': 'Bearer ' + encoded_jwt,
        'Accept': 'application/vnd.github+json',
        'X-GitHub-Api-Version': '2022-11-28'
    }
    request = urllib.request.Request(url, headers=headers, method='POST')
    response = urllib.request.urlopen(request)
    response_json = json.loads(response.read().decode())
    return response_json['token']


def verify_new_repo(token, cac_org, new_repo):
    # Attempt to view the new repo
    try:
        url = 'https://api.github.com/repos/' + cac_org + '/' + new_repo
        headers = {
            'Accept': 'application/vnd.github+json',
            'Authorization': 'Bearer ' + token,
            'X-GitHub-Api-Version': '2022-11-28'
        }
        request = urllib.request.Request(url, headers=headers)
        urllib.request.urlopen(request)
        return True
    except:
        return False


def encrypt(public_key_for_repo: str, secret_value_input: str) -> str:
    """Encrypt a Unicode string using the public key."""
    sealed_box = public.SealedBox(public.PublicKey(public_key_for_repo.encode("utf-8"), encoding.Base64Encoder()))
    encrypted = sealed_box.encrypt(secret_value_input.encode("utf-8"))
    return b64encode(encrypted).decode("utf-8")


def get_public_key(gh_base_url: str, gh_owner: str, gh_repo: str, gh_auth_token: str) -> (str, str):
    public_key_endpoint: str = f"{gh_base_url}/{gh_owner}/{gh_repo}/actions/secrets/public-key"
    headers: TypedDict[str, str] = {"Authorization": f"Bearer {gh_auth_token}"}
    response = requests.get(url=public_key_endpoint, headers=headers)
    if response.status_code != 200:
        raise IOError(
            f"Could not get public key for repository {gh_owner}/{gh_repo}. The Response code was {response.status_code}")

    public_key_json = response.json()
    return public_key_json['key_id'], public_key_json['key']


def set_secret(gh_base_url: str, gh_owner: str, gh_repo: str, gh_auth_token: str, public_key_id: str, secret_key: str,
               encrypted_secret_value: str):
    secret_creation_url = f"{gh_base_url}/{gh_owner}/{gh_repo}/actions/secrets/{secret_key}"
    secret_creation_body = {"key_id": public_key_id, "encrypted_value": encrypted_secret_value}
    headers: TypedDict[str, str] = {"Authorization": f"Bearer {gh_auth_token}", "Content-Type": "application/json"}

    secret_creation_response = requests.put(url=secret_creation_url, json=secret_creation_body, headers=headers)
    if secret_creation_response.status_code == 201 or secret_creation_response.status_code == 204:
        print("--Secret Created / Updated!--")
    else:
        print(f"-- Error creating / updating github secret, the reason was : {secret_creation_response.reason}")


parser, _ = init_argparse()

if not parser.git_password.strip() and not (
        parser.github_app_id.strip() and parser.github_app_private_key.strip() and parser.github_app_installation_id.strip()):
    print("You must supply the GitHub token, or the GitHub App ID and private key and installation ID")
    sys.exit(1)

if not parser.git_organization.strip():
    print("You must define the organization")
    sys.exit(1)

if not parser.repo.strip():
    print("You must define the repo name")
    sys.exit(1)

token = generate_github_token(parser.github_app_id, parser.github_app_private_key,
                              parser.github_app_installation_id) if len(
    parser.git_password.strip()) == 0 else parser.git_password.strip()

if not parser.git_password.strip() and not (
        parser.github_app_id.strip() and parser.github_app_private_key.strip() and parser.github_app_installation_id.strip()):
    print("You must supply the GitHub token, or the GitHub App ID and private key and installation ID")
    sys.exit(1)

if not parser.git_organization.strip():
    print("You must define the organization")
    sys.exit(1)

if not parser.repo.strip():
    print("You must define the repo name")
    sys.exit(1)

if not parser.secret_name.strip():
    print("You must define the secret name")
    sys.exit(1)

if not verify_new_repo(token, parser.git_organization, parser.repo):
    print("Could not find the repo")
    sys.exit(1)

key_id, public_key = get_public_key('https://api.github.com/repos', parser.git_organization, parser.repo,
                                    token)
encrypted_secret: str = encrypt(public_key_for_repo=public_key, secret_value_input=parser.secret_value)
set_secret(gh_base_url='https://api.github.com/repos', gh_owner=parser.git_organization, gh_repo=parser.repo,
           gh_auth_token=token, public_key_id=key_id, secret_key=parser.secret_name,
           encrypted_secret_value=encrypted_secret)

Provided under the Apache License version 2.0.

Report an issue

To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.

{
  "Id": "8d59cae3-3168-466e-9490-bf654c180660",
  "Name": "GitHub - Create Repo Secret",
  "Description": "This step creates a secret in a GitHub repo.",
  "Version": 1,
  "ExportedAt": "2023-10-19T01:59:46.768Z",
  "ActionType": "Octopus.Script",
  "Author": "mcasperson",
  "Packages": [],
  "Parameters": [
    {
      "Id": "6470d539-d137-42dd-bff2-9ebc1955b2a7",
      "Name": "CreateGitHubSecret.GitHub.Secret.Name",
      "Label": "Secret Name",
      "HelpText": "The name of the GitHub secret.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "2ead2e13-1a01-4360-9585-f920181880a1",
      "Name": "CreateGitHubSecret.GitHub.Secret.Value",
      "Label": "Secret Value",
      "HelpText": "The secret value.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Sensitive"
      }
    },
    {
      "Id": "643b6230-5cca-4ca2-8340-9624ed721b9b",
      "Name": "CreateGitHubSecret.Git.Url.Repo",
      "Label": "GitHub Repo Name",
      "HelpText": "The GitHub repo name i.e. `myrepo` in the URL`https://github.com/owner/myrepo`.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "8c506ad7-f8b9-458c-a53b-23a19984c413",
      "Name": "CreateGitHubSecret.Git.Url.Organization",
      "Label": "Github Owner",
      "HelpText": "The GitHub repo owner or organization i.e. `owner` in the URL `https://github.com/owner/myrepo`.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "a457faef-6cd8-4c1b-ad23-306b03419794",
      "Name": "CreateGitHubSecret.Git.Credentials.Password",
      "Label": "GitHub Access Token",
      "HelpText": "The GitHub access token",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Sensitive"
      }
    }
  ],
  "Properties": {
    "Octopus.Action.RunOnServer": "true",
    "Octopus.Action.Script.ScriptSource": "Inline",
    "Octopus.Action.Script.Syntax": "Python",
    "Octopus.Action.Script.ScriptBody": "# https://gist.github.com/comdotlinux/9a53bb00767a16d6646464c4b8249094\n\n# This script forks a GitHub repo. It creates a token from a GitHub App installation to avoid\n# having to use a regular user account.\nimport subprocess\nimport sys\n\n# Install our own dependencies\nsubprocess.check_call([sys.executable, '-m', 'pip', 'install', 'jwt', '--disable-pip-version-check'])\nsubprocess.check_call([sys.executable, '-m', 'pip', 'install', 'pynacl', '--disable-pip-version-check'])\n\nimport requests\nimport json\nimport sys\nimport os\nimport urllib.request\nimport base64\nimport re\nimport jwt\nimport time\nimport argparse\nimport urllib3\nfrom base64 import b64encode\nfrom typing import TypedDict\nfrom nacl import public, encoding\n\n# Disable insecure http request warnings\nurllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\n\n# If this script is not being run as part of an Octopus step, setting variables is a noop\nif 'set_octopusvariable' not in globals():\n    def set_octopusvariable(variable, value):\n        pass\n\n# If this script is not being run as part of an Octopus step, return variables from environment variables.\n# Periods are replaced with underscores, and the variable name is converted to uppercase\nif \"get_octopusvariable\" not in globals():\n    def get_octopusvariable(variable):\n        return os.environ[re.sub('\\\\.', '_', variable.upper())]\n\n# If this script is not being run as part of an Octopus step, print directly to std out.\nif 'printverbose' not in globals():\n    def printverbose(msg):\n        print(msg)\n\n\ndef printverbose_noansi(output):\n    \"\"\"\n    Strip ANSI color codes and print the output as verbose\n    :param output: The output to print\n    \"\"\"\n    output_no_ansi = re.sub(r'\\x1b\\[[0-9;]*m', '', output)\n    printverbose(output_no_ansi)\n\n\ndef get_octopusvariable_quiet(variable):\n    \"\"\"\n    Gets an octopus variable, or an empty string if it does not exist.\n    :param variable: The variable name\n    :return: The variable value, or an empty string if the variable does not exist\n    \"\"\"\n    try:\n        return get_octopusvariable(variable)\n    except:\n        return ''\n\n\ndef init_argparse():\n    parser = argparse.ArgumentParser(\n        usage='%(prog)s [OPTION]',\n        description='Fork a GitHub repo'\n    )\n\n    parser.add_argument('--secret-name', action='store',\n                        default=get_octopusvariable_quiet(\n                            'CreateGitHubSecret.GitHub.Secret.Name') or get_octopusvariable_quiet(\n                            'GitHub.Secret.Name'))\n    parser.add_argument('--secret-value', action='store',\n                        default=get_octopusvariable_quiet(\n                            'CreateGitHubSecret.GitHub.Secret.Value') or get_octopusvariable_quiet(\n                            'GitHub.Secret.Value'))\n\n    parser.add_argument('--repo', action='store',\n                        default=get_octopusvariable_quiet(\n                            'CreateGitHubSecret.Git.Url.Repo') or get_octopusvariable_quiet(\n                            'Git.Url.Repo') or get_octopusvariable_quiet('Octopus.Project.Name'))\n    parser.add_argument('--git-organization', action='store',\n                        default=get_octopusvariable_quiet(\n                            'CreateGitHubSecret.Git.Url.Organization') or get_octopusvariable_quiet(\n                            'Git.Url.Organization'))\n    parser.add_argument('--github-app-id', action='store',\n                        default=get_octopusvariable_quiet(\n                            'CreateGitHubSecret.GitHub.App.Id') or get_octopusvariable_quiet('GitHub.App.Id'))\n    parser.add_argument('--github-app-installation-id', action='store',\n                        default=get_octopusvariable_quiet(\n                            'CreateGitHubSecret.GitHub.App.InstallationId') or get_octopusvariable_quiet(\n                            'GitHub.App.InstallationId'))\n    parser.add_argument('--github-app-private-key', action='store',\n                        default=get_octopusvariable_quiet(\n                            'CreateGitHubSecret.GitHub.App.PrivateKey') or get_octopusvariable_quiet(\n                            'GitHub.App.PrivateKey'))\n    parser.add_argument('--git-password', action='store',\n                        default=get_octopusvariable_quiet(\n                            'CreateGitHubSecret.Git.Credentials.Password') or get_octopusvariable_quiet(\n                            'Git.Credentials.Password'),\n                        help='The git password. This takes precedence over the --github-app-id,  --github-app-installation-id, and --github-app-private-key')\n\n    return parser.parse_known_args()\n\n\ndef generate_github_token(github_app_id, github_app_private_key, github_app_installation_id):\n    # Generate the tokens used by git and the GitHub API\n    app_id = github_app_id\n    signing_key = jwt.jwk_from_pem(github_app_private_key.encode('utf-8'))\n\n    payload = {\n        # Issued at time\n        'iat': int(time.time()),\n        # JWT expiration time (10 minutes maximum)\n        'exp': int(time.time()) + 600,\n        # GitHub App's identifier\n        'iss': app_id\n    }\n\n    # Create JWT\n    jwt_instance = jwt.JWT()\n    encoded_jwt = jwt_instance.encode(payload, signing_key, alg='RS256')\n\n    # Create access token\n    url = 'https://api.github.com/app/installations/' + github_app_installation_id + '/access_tokens'\n    headers = {\n        'Authorization': 'Bearer ' + encoded_jwt,\n        'Accept': 'application/vnd.github+json',\n        'X-GitHub-Api-Version': '2022-11-28'\n    }\n    request = urllib.request.Request(url, headers=headers, method='POST')\n    response = urllib.request.urlopen(request)\n    response_json = json.loads(response.read().decode())\n    return response_json['token']\n\n\ndef verify_new_repo(token, cac_org, new_repo):\n    # Attempt to view the new repo\n    try:\n        url = 'https://api.github.com/repos/' + cac_org + '/' + new_repo\n        headers = {\n            'Accept': 'application/vnd.github+json',\n            'Authorization': 'Bearer ' + token,\n            'X-GitHub-Api-Version': '2022-11-28'\n        }\n        request = urllib.request.Request(url, headers=headers)\n        urllib.request.urlopen(request)\n        return True\n    except:\n        return False\n\n\ndef encrypt(public_key_for_repo: str, secret_value_input: str) -> str:\n    \"\"\"Encrypt a Unicode string using the public key.\"\"\"\n    sealed_box = public.SealedBox(public.PublicKey(public_key_for_repo.encode(\"utf-8\"), encoding.Base64Encoder()))\n    encrypted = sealed_box.encrypt(secret_value_input.encode(\"utf-8\"))\n    return b64encode(encrypted).decode(\"utf-8\")\n\n\ndef get_public_key(gh_base_url: str, gh_owner: str, gh_repo: str, gh_auth_token: str) -> (str, str):\n    public_key_endpoint: str = f\"{gh_base_url}/{gh_owner}/{gh_repo}/actions/secrets/public-key\"\n    headers: TypedDict[str, str] = {\"Authorization\": f\"Bearer {gh_auth_token}\"}\n    response = requests.get(url=public_key_endpoint, headers=headers)\n    if response.status_code != 200:\n        raise IOError(\n            f\"Could not get public key for repository {gh_owner}/{gh_repo}. The Response code was {response.status_code}\")\n\n    public_key_json = response.json()\n    return public_key_json['key_id'], public_key_json['key']\n\n\ndef set_secret(gh_base_url: str, gh_owner: str, gh_repo: str, gh_auth_token: str, public_key_id: str, secret_key: str,\n               encrypted_secret_value: str):\n    secret_creation_url = f\"{gh_base_url}/{gh_owner}/{gh_repo}/actions/secrets/{secret_key}\"\n    secret_creation_body = {\"key_id\": public_key_id, \"encrypted_value\": encrypted_secret_value}\n    headers: TypedDict[str, str] = {\"Authorization\": f\"Bearer {gh_auth_token}\", \"Content-Type\": \"application/json\"}\n\n    secret_creation_response = requests.put(url=secret_creation_url, json=secret_creation_body, headers=headers)\n    if secret_creation_response.status_code == 201 or secret_creation_response.status_code == 204:\n        print(\"--Secret Created / Updated!--\")\n    else:\n        print(f\"-- Error creating / updating github secret, the reason was : {secret_creation_response.reason}\")\n\n\nparser, _ = init_argparse()\n\nif not parser.git_password.strip() and not (\n        parser.github_app_id.strip() and parser.github_app_private_key.strip() and parser.github_app_installation_id.strip()):\n    print(\"You must supply the GitHub token, or the GitHub App ID and private key and installation ID\")\n    sys.exit(1)\n\nif not parser.git_organization.strip():\n    print(\"You must define the organization\")\n    sys.exit(1)\n\nif not parser.repo.strip():\n    print(\"You must define the repo name\")\n    sys.exit(1)\n\ntoken = generate_github_token(parser.github_app_id, parser.github_app_private_key,\n                              parser.github_app_installation_id) if len(\n    parser.git_password.strip()) == 0 else parser.git_password.strip()\n\nif not parser.git_password.strip() and not (\n        parser.github_app_id.strip() and parser.github_app_private_key.strip() and parser.github_app_installation_id.strip()):\n    print(\"You must supply the GitHub token, or the GitHub App ID and private key and installation ID\")\n    sys.exit(1)\n\nif not parser.git_organization.strip():\n    print(\"You must define the organization\")\n    sys.exit(1)\n\nif not parser.repo.strip():\n    print(\"You must define the repo name\")\n    sys.exit(1)\n\nif not parser.secret_name.strip():\n    print(\"You must define the secret name\")\n    sys.exit(1)\n\nif not verify_new_repo(token, parser.git_organization, parser.repo):\n    print(\"Could not find the repo\")\n    sys.exit(1)\n\nkey_id, public_key = get_public_key('https://api.github.com/repos', parser.git_organization, parser.repo,\n                                    token)\nencrypted_secret: str = encrypt(public_key_for_repo=public_key, secret_value_input=parser.secret_value)\nset_secret(gh_base_url='https://api.github.com/repos', gh_owner=parser.git_organization, gh_repo=parser.repo,\n           gh_auth_token=token, public_key_id=key_id, secret_key=parser.secret_name,\n           encrypted_secret_value=encrypted_secret)\n"
  },
  "Category": "GitHub",
  "HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/github-create-secret.json",
  "Website": "/step-templates/8d59cae3-3168-466e-9490-bf654c180660",
  "Logo": "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",
  "$Meta": {
    "Type": "ActionTemplate"
  }
}

History

Page updated on Thursday, October 19, 2023