Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3fd1811
feature: create a rock for the application
edisile Feb 23, 2026
81d84d3
feature: create charm for deployment
edisile Feb 23, 2026
9b16579
feature: github actions for rock test on PR and deploy
edisile Feb 23, 2026
73a2afe
fix: copy static files correctly in rockcraft config
edisile Feb 23, 2026
a330390
fix: cleanup before merging into deploy branches
edisile Feb 23, 2026
4257425
fix: add deleted.yaml to rock
edisile Feb 23, 2026
a474b47
fix: disable charm tracing interface
edisile Feb 23, 2026
6f2d049
fix: rename charm class
edisile Feb 23, 2026
41f8fa4
fix: update PaaS charm link
edisile Feb 23, 2026
6ff0d05
fix: added env variables to charmcraft.yaml
edisile Feb 23, 2026
b9e17c9
fix: import webapp.config at the top of app module
edisile Feb 23, 2026
77c36bc
chore: remove unused env var
edisile Feb 23, 2026
7dc4cda
chore: env vars descriptions
edisile Feb 23, 2026
da49676
fix: lining, duplicate import
edisile Feb 23, 2026
de9a301
fix: reduce token permissions in github workflows
edisile Feb 23, 2026
d19531f
force deploy
edisile Feb 23, 2026
f0092c9
fix: workflow permissions
edisile Feb 23, 2026
b11eb6c
fix: add missing store-api env vars
edisile Feb 23, 2026
07f2499
fix: reproducible JS builds in rock OCI
edisile Feb 23, 2026
33e2441
fix: charm docs spelling
edisile Feb 23, 2026
636ced7
fix: use actions/checkout@v6 for rock packing
edisile Feb 23, 2026
1e44afc
feature: "Staging API" env deploy action
edisile Feb 23, 2026
43cfa0f
fix: new version of deploy action
edisile Feb 23, 2026
a3ed5d3
fix: security.md
edisile Feb 23, 2026
d6eb918
fix: copilot suggestions
edisile Feb 23, 2026
da9a37a
fix: add report sheet URL config to
edisile Feb 23, 2026
7456e79
Update .github/workflows/deploy.yaml
edisile Feb 23, 2026
004f06a
Set up Demos on PS7 for charmed snapcraft.io
alvaromateo Mar 31, 2026
743e29a
Fix wrong secret id in terraform plan
alvaromateo Apr 1, 2026
e304ed3
Fix redis-k8s charm definition
alvaromateo Apr 1, 2026
3ae9f64
Add redis interface
alvaromateo Apr 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/cleanup-demo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Demo Cleanup
on:
pull_request:
types:
- closed
permissions:
pull-requests: write
packages: write

jobs:
cleanup:
name: Cleanup Demo
uses: canonical/webteam-devops/.github/workflows/cleanup-demo.yaml@demos
with:
juju-model-name: "795798e4-922f-49c7-9169-004ffc17df90@serviceaccount/k8s-marketplace-demos-default"
secrets:
demos_juju_client_id: ${{ secrets.DEMOS_JUJU_CLIENT_ID }}
demos_juju_client_secret: ${{ secrets.DEMOS_JUJU_CLIENT_SECRET }}
demos_s3_access_key_id: ${{ secrets.DEMOS_S3_ACCESS_KEY_ID }}
demos_s3_secret_access_key: ${{ secrets.DEMOS_S3_SECRET_ACCESS_KEY }}
28 changes: 28 additions & 0 deletions .github/workflows/demo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Demo
on:
pull_request:
types:
- opened
- reopened
- synchronize
permissions:
pull-requests: write
packages: write

# Ensure only one demo runs at a time.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
deploy:
name: Deploy Demo
uses: canonical/webteam-devops/.github/workflows/start-demo.yaml@demos
with:
juju-model-name: "795798e4-922f-49c7-9169-004ffc17df90@serviceaccount/k8s-marketplace-demos-default"
juju-model-uuid: "b765a126-883d-440b-847d-0bd30a4f8318"
secrets:
demos_juju_client_id: ${{ secrets.DEMOS_JUJU_CLIENT_ID }}
demos_juju_client_secret: ${{ secrets.DEMOS_JUJU_CLIENT_SECRET }}
demos_s3_access_key_id: ${{ secrets.DEMOS_S3_ACCESS_KEY_ID }}
demos_s3_secret_access_key: ${{ secrets.DEMOS_S3_SECRET_ACCESS_KEY }}
21 changes: 21 additions & 0 deletions .github/workflows/deploy-staging-api.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Pack and Deploy Staging API

on:
push:
branches:
- main

jobs:
deploy-staging-api-env-on-merge-into-main:
# dispatch another copy of the deploy.yaml workflow that deploys the Staging API env
uses: ./.github/workflows/deploy.yaml
permissions:
contents: read
deployments: write
packages: write
with:
environment: Staging API
secrets:
VAULT_APPROLE_ROLE_ID: ${{ secrets.VAULT_APPROLE_ROLE_ID }}
VAULT_APPROLE_SECRET_ID: ${{ secrets.VAULT_APPROLE_SECRET_ID }}
CHARMHUB_TOKEN: ${{ secrets.CHARMHUB_TOKEN }}
64 changes: 64 additions & 0 deletions .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Pack and Deploy

on:
push:
branches:
- main
- staging
workflow_call:
inputs:
environment:
description: 'Environment (Production, Staging or Staging API)'
required: true
type: string
workflow_dispatch:
inputs:
environment:
description: 'Environment (Production, Staging or Staging API)'
required: true
type: choice
options:
- Production
- Staging
- Staging API

jobs:
setup:
runs-on: ubuntu-latest
permissions:
contents: read
environment: ${{ github.event.inputs.environment != '' && github.event.inputs.environment || (github.ref == 'refs/heads/main' && 'Production' || 'Staging') }}
outputs:
charm_name: ${{ steps.setup-vars.outputs.charm_name }}
channel: ${{ steps.setup-vars.outputs.channel }}
juju_controller_name: ${{ steps.setup-vars.outputs.juju_controller_name }}
juju_model_name: ${{ steps.setup-vars.outputs.juju_model_name }}
environment: ${{ steps.setup-vars.outputs.environment }}
steps:
- name: setup vars
id: setup-vars
run: |
echo "charm_name=${{ vars.CHARM_NAME }}" >> $GITHUB_OUTPUT
echo "channel=${{ vars.CHANNEL }}" >> $GITHUB_OUTPUT
echo "juju_controller_name=${{ vars.JUJU_CONTROLLER_NAME }}" >> $GITHUB_OUTPUT
echo "juju_model_name=${{ vars.JUJU_MODEL_NAME }}" >> $GITHUB_OUTPUT
echo "environment=${{ github.event.inputs.environment != '' && github.event.inputs.environment || (github.ref == 'refs/heads/main' && 'Production' || 'Staging') }}" >> $GITHUB_OUTPUT

deploy:
needs: setup
name: Deploy
uses: canonical/webteam-devops/.github/workflows/deploy.yaml@main
permissions:
contents: read
deployments: write
packages: write
with:
environment: ${{ needs.setup.outputs.environment }}
charm_name: ${{ needs.setup.outputs.charm_name }}
channel: ${{ needs.setup.outputs.channel }}
juju_controller_name: ${{ needs.setup.outputs.juju_controller_name }}
juju_model_name: ${{ needs.setup.outputs.juju_model_name }}
secrets:
VAULT_APPROLE_ROLE_ID: ${{ secrets.VAULT_APPROLE_ROLE_ID }}
VAULT_APPROLE_SECRET_ID: ${{ secrets.VAULT_APPROLE_SECRET_ID }}
CHARMHUB_TOKEN: ${{ secrets.CHARMHUB_TOKEN }}
16 changes: 16 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,22 @@ jobs:
- 'package.json'
- 'yarn.lock'

pack-rock:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6

- name: Setup LXD
uses: canonical/setup-lxd@main

- name: Setup rockcraft
run: sudo snap install rockcraft --classic

- name: Pack rock
run: rockcraft pack

lint-python:
needs: changes
if: ${{ needs.changes.outputs.py == 'true' }}
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,7 @@ coverage/
.webcache_blog/
.coverage
cypress/screenshots/

# Charming artifacts
*.charm
*.rock
15 changes: 15 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# This file serves as an entry point for the rock image. It is required by the PaaS app charmer.
# The flask application must be defined in this file under the variable name `app`.
# See - https://documentation.ubuntu.com/rockcraft/en/latest/reference/extensions/flask-framework/
import os
import logging

# canonicalwebteam.flask-base requires SECRET_KEY to be set, this must be done before importing the app
os.environ["SECRET_KEY"] = os.environ["FLASK_SECRET_KEY"]

# disable talisker logger, as it is not used in this application and clutters logs
logging.getLogger("talisker.context").disabled = True

from webapp.app import create_app

app = create_app()
10 changes: 10 additions & 0 deletions charm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
venv/
build/
*.charm
.tox/
.coverage
__pycache__/
*.py[cod]
.idea
.vscode/
lib/
55 changes: 55 additions & 0 deletions charm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# The Charm for the snapcraft.io website

This charm was created using the [PaaS App Charmer](https://canonical-12-factor-app-support.readthedocs-hosted.com/latest/)

## Local development

To work on this charm locally, you first need to set up an environment, follow [this section](https://juju.is/docs/sdk/write-your-first-kubernetes-charm-for-a-flask-app#heading--set-things-up) of the tutorial.

Then, you can run the following command to pack and upload the rock:

```bash
rockcraft pack
rockcraft.skopeo --insecure-policy copy --dest-tls-verify=false oci-archive:snapcraft-io*.rock docker://localhost:32000/snapcraft-io:1
```

This will pack the application into a [rock](https://documentation.ubuntu.com/rockcraft/en/latest/explanation/rocks/) (OCI image) and upload it to the local registry.

You can deploy the charm locally with:

```bash
cd charm
charmcraft fetch-libs
charmcraft pack
juju deploy ./*.charm --resource flask-app-image=localhost:32000/snapcraft-io:1
```

This will deploy the charm with the rock image you just uploaded attached as a resource.

Once `juju status` reports the charm as `active`, you can test the webserver:

```bash
curl {IP_OF_SNAPCRAFT_IO_UNIT}:8000
```

To connect using a browser, the easiest way is to integrate with `nginx-ingress-integrator`:

```bash
juju deploy nginx-ingress-integrator --trust
juju config nginx-ingress-integrator service-hostname=snapcraft.local path-routes=/
juju integrate nginx-ingress-integrator snapcraft-io
```

You can then add `snapcraft.local` to your `/etc/hosts` file with the IP of the multipass vm:

```bash
multipass ls # Get the IP of the VM
echo "{IP_OF_VM} snapcraft.local" | sudo tee -a /etc/hosts
```

> Note: login will not work using this setup, if you'd like to access publisher pages, change the domain to `staging.snapcraft.io`, but make sure to remove the line from `/etc/hosts` after you're done.


## Design Decisions:
- To keep the codebase clean and charm libraries updated, they are only fetched before packing the charm in the [GitHub Actions workflow](https://github.com/canonical/webteam-devops/blob/7041da8810758715a73e1f8be67b2e68f0e1d58f/.github/workflows/deploy.yaml#L97).
- As all our work is open source, the charm is publicly available on [snapcraft](https://charmhub.io/snapcraft-io), the rock image is also included as a resource. This significantly simplifies deployment.
131 changes: 131 additions & 0 deletions charm/charmcraft.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
name: snapcraft-io

type: charm

bases:
- build-on:
- name: ubuntu
channel: "22.04"
run-on:
- name: ubuntu
channel: "22.04"

summary: The charm for the snapcraft.io website

description: The charm for the snapcraft.io website, built with the PaaS app charmer

extensions:
- flask-framework

requires:
redis:
interface: redis
optional: true
limit: 1

config:
options:
sentry-dsn:
description: "Sentry Data Source Name for the project"
type: string

environment:
description: "Environment in which the application is running, mostly useless for the charmed version of the app"
default: "production"
type: string

marketo-client-id:
description: "Marketo API client ID"
type: secret

marketo-client-secret:
description: "Marketo API client secret"
type: secret

github-client-id:
description: "GitHub OAuth application ID for prompting users for access to their repositories"
type: string

github-client-secret:
description: "GitHub OAuth application client secret for prompting users for access to their repositories"
type: secret

github-snapcraft-user-token:
description: "GitHub application token for automated builds"
type: secret

github-snapcraft-bot-user-token:
description: "GitHub application token for CVE data"
type: secret

github-webhook-secret:
description: "Secret salt used for signing automated build webhooks"
type: secret

github-webhook-host-url:
description: "URL of the automated build webhooks' host"
type: string

lp-api-username:
description: "Launchpad API username"
type: string

lp-api-token:
description: "Launchpad API token"
type: secret

lp-api-token-secret:
description: "Launchpad API secret"
type: secret

youtube-api-key:
description: "API key used to access the YouTube Data API for retrieving and displaying YouTube video content on snapcraft.io"
type: secret

discourse-api-key:
description: "API key used by the application to authenticate with the configured Discourse forum"
type: secret

discourse-api-username:
description: "Discourse username to associate with API requests to the Discourse forum"
type: string

dns-verification-salt:
description: "Secret salt used when generating DNS verification tokens to confirm domain ownership"
type: secret

login-url:
description: "Base URL for SSO login redirects"
default: "https://login.ubuntu.com"
type: string

bsi-url:
description: "Base URL for the Build Snapcraft IO service used for automated builds"
default: "https://build.snapcraft.io"
type: string

snapstore-dashboard-api-url:
description: "Base URL for SCA backend"
default: "https://dashboard.snapcraft.io/"
type: string

publishergw-url:
description: "Base URL for Publisher Gateway API"
default: "https://api.charmhub.io"
type: string

devicegw-url:
description: "Base URL for Device Gateway API"
default: "https://api.snapcraft.io/"
type: string

report-sheet-url:
description: "URL for the reported snaps spreadsheet on Google docs"
type: string


# requires:
# tracing:
# interface: tracing
# optional: true
# limit: 1
2 changes: 2 additions & 0 deletions charm/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ops ~= 2.17
paas-charm>=1.0,<2
Loading
Loading