Publish with GitHub Actions
These instructions help you publish programmatically via GitHub Actions into a Posit Connect installation hosted in Snowflake Snowpark Container Services (SPCS).
CI/CD with GitHub Actions
GitHub Actions lets you build workflows for continuous integration (CI) and continuous deployment (CD). These instructions use a workflow to publish updates from GitHub to Connect. The workflow drives publishing with rsconnect-python, which interacts with Connect through its API.
Use the Connect Server API to fully automate most actions, such as deploying content, adding users to content, or customizing settings. API endpoints can be called directly or teams can integrate client packages like rsconnect-python into their CI/CD systems.
Code Promotion Example Flow
- Develop your app in Posit Workbench running in your Snowflake development account.
- Test in development by deploying to Posit Connect running in your Snowflake development account using the publish-inside-snowflake workflow.
- Promote to production - by deploying to Posit Connect running in your Snowflake production account. Authenticate across accounts using profiles created in a connections.toml file.
Configure credentials and secrets
You must have write access to your GitHub repository and the ability to configure GitHub Actions secrets.
Connect API Key
Visit your Posit Connect installation and provision an API key. You will later use this key to create the CONNECT_SERVER_API_KEY GitHub secret.
Snowflake credentials
You need a Snowflake service user with:
- Username: e.g.,
GITHUB_ACTIONS - Private Key: RSA private key for JWT authentication (PEM format)
- Private Key Passphrase: Password for the private key
- Account: Your Snowflake account identifier (e.g.,
<orgname>-<account_name>)
Create a Snowflake service user within each account targeted for publishing.
The below code generates an encrypted private key when configuring key-pair authentication for your account.
Terminal
# Create public/private key files with encryption
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub
chmod 600 rsa_key.p8
# Copy your public key contents (macOS)
grep -v '\-' rsa_key.pub | pbcopy
# Or manually copy the output (Linux/Windows)
grep -v '\-' rsa_key.pubConfigure GitHub Secrets
GitHub secrets can be configured using the GitHub CLI or via the GitHub user interface.
| Secret Name | Description | Example Value |
|---|---|---|
CONNECT_SERVER |
External Connect URL where you are publishing to | https://abcde-<orgname>-<account_name>.snowflakecomputing.app |
CONNECT_SERVER_API_KEY |
Connect API key | abcd1234... |
SNOWFLAKE_PRIVATE_KEY |
Snowflake RSA private key (PEM format) | -----BEGIN ENCRYPTED PRIVATE KEY-----\n... |
SNOWFLAKE_PRIVATE_KEY_PASSPHRASE |
Private key passphrase | your-passphrase |
Create your GitHub setup-snowflake action
Create .github/actions/setup-snowflake/action.yml in your repository to set up account authentication:
name: Setup Snowflake Environment
inputs:
username:
description: Snowflake Username
required: true
private-key:
description: Snowflake Private Key
required: true
private-key-passphrase:
description: Snowflake Private Key Passphrase
required: true
connection:
description: Snowflake Connection Name
default: "default"
runs:
using: "composite"
steps:
- name: Write Snowflake Configuration
shell: bash
run: |
mkdir -p ~/.snowflake
chmod 700 ~/.snowflake
echo "${{ inputs.private-key }}" > ~/.snowflake/rsa_key.p8
chmod 600 ~/.snowflake/rsa_key.p8
cat << EOF > ~/.snowflake/connections.toml
[${{ inputs.connection }}]
account = "<orgname>-<account_name>"
user = "${{ inputs.username }}"
authenticator = "SNOWFLAKE_JWT"
private_key_file = "${HOME}/.snowflake/rsa_key.p8"
private_key_file_pwd = "${{ inputs.private-key-passphrase }}"
EOF
chmod 600 ~/.snowflake/connections.tomlTo publish across multiple Snowflake environments, configure your setup-snowflake action above to create multiple connection profiles in the connections.toml file.
Create your GitHub workflow file
Create .github/workflows/publish-connect-app.yml in your repository:
name: Publish Shiny Python App to Connect
on:
push:
branches:
- main
jobs:
publish:
name: Publish to Staging Connect
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python and uv
uses: astral-sh/setup-uv@v8
with:
enable-cache: true
- name: Setup Snowflake
uses: ./.github/actions/setup-snowflake
with:
username: "GITHUB_ACTIONS"
private-key: "${{ secrets.SNOWFLAKE_PRIVATE_KEY }}"
private-key-passphrase: "${{ secrets.SNOWFLAKE_PRIVATE_KEY_PASSPHRASE }}"
connection: "<orgname>-<account_name>"
- name: Install rsconnect-python with Snowflake support
run: |
# Install rsconnect-python with snowflake extras
uv tool install rsconnect-python --with snowflake-cli-labs
- name: Generate manifest and publish to target Connect server
env:
CONNECT_SERVER: ${{ secrets.CONNECT_SERVER }}
CONNECT_API_KEY: ${{ secrets.CONNECT_SERVER_API_KEY }}
run: |
# Add uv tool bin directory to PATH
export PATH="$HOME/.local/bin:$PATH"
# Generate manifest
rsconnect write-manifest shiny \
--overwrite \
--entrypoint app:app \
.
# Deploy using rsconnect CLI with Snowflake connection
rsconnect deploy manifest manifest.json \
--server "${CONNECT_SERVER}" \
--api-key "${CONNECT_SERVER_API_KEY}" \
--snowflake-connection-name "<orgname>-<account_name>"This workflow runs on any push request to main. The GitHub documentation about workflow triggers explains other types of events you can use.