diff --git a/.github/workflows/delivery.yml b/.github/workflows/delivery.yml new file mode 100644 index 0000000..1730a6b --- /dev/null +++ b/.github/workflows/delivery.yml @@ -0,0 +1,43 @@ +name: Delivery + +on: + push: + branches: [ master ] + release: + # Note: a current limitation is that when a release is edited after publication, then the Docker tags are not automatically updated. + types: [ published ] + +permissions: + contents: write + packages: write + +jobs: + publish-docker-image: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=semver,pattern={{major}}.{{minor}}.{{patch}} + type=raw,value=edge + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build container and push to GitHub Container Registry + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/.github/workflows/status-checks.yml b/.github/workflows/status-checks.yml new file mode 100644 index 0000000..8e00ebf --- /dev/null +++ b/.github/workflows/status-checks.yml @@ -0,0 +1,16 @@ +name: Status checks + +on: + push: + branches: [ master ] + pull_request: + # Make it possible to trigger the checks manually. + workflow_dispatch: + +jobs: + docker-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run Dockerfile build stage + run: docker build -t privacybydesign/attribute-index:build . \ No newline at end of file diff --git a/.gitignore b/.gitignore index 182574b..4593921 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ en/ nl/ node_modules/ script.js* +repos/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ac94edd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +FROM python:3.9-slim + +WORKDIR / + +RUN apt-get update && \ + apt-get install -y curl apache2 && \ + curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \ + apt-get install -y nodejs && \ + npm install -g yarn && \ + pip install Jinja2 && \ + pip install requests + +ENV NODE_OPTIONS=--openssl-legacy-provider + +COPY . . +RUN python3 download_repos.py && \ + python3 -u update.py && \ + test -f index.json && \ + yarn && yarn build && \ + mkdir -p /var/www/html && \ + cp -r /en /var/www/html/ && \ + cp -r /nl /var/www/html/ && \ + cp -r /repos /var/www/html/ && \ + cp style.css /var/www/html/ && \ + cp logo.svg /var/www/html/ && \ + cp script.js /var/www/html/ && \ + cp index.json /var/www/html/ + +EXPOSE 80 + +CMD ["apache2ctl", "-D", "FOREGROUND"] diff --git a/README.markdown b/README.markdown index cd07917..9249cbf 100644 --- a/README.markdown +++ b/README.markdown @@ -15,7 +15,6 @@ Dependencies: Before generating content, download the scheme managers by running `download_repos.py`. To add a scheme, configure the schemes config in `config.json`. - ## Running To generate the HTML for the attribute index, run the script: @@ -30,6 +29,13 @@ To generate the JavaScript handling issuance sessions of demo credentials, run: yarn yarn run build +## Running with Docker + +To build and run the Docker container, build and run the docker image via the following: + + docker build -t attribute-index . + docker run -p 80:80 attribute-index + ## Using untrusted scheme managers Currently, scheme managers are considered trusted. Generating an attribute index diff --git a/config.json b/config.json index 3dc7b64..d7170f2 100644 --- a/config.json +++ b/config.json @@ -1,15 +1,15 @@ [ { - "source": "repos/pbdf-schememanager", - "github": "https://github.com/privacybydesign/pbdf-schememanager/blob/master" + "PATH": "repos/pbdf-schememanager", + "url": "https://github.com/privacybydesign/pbdf-schememanager/archive/refs/heads/master.zip" }, { - "source": "repos/irma-demo-schememanager", - "github": "https://github.com/privacybydesign/irma-demo-schememanager/blob/master" + "PATH": "repos/irma-demo-schememanager", + "url": "https://github.com/privacybydesign/irma-demo-schememanager/archive/refs/heads/master.zip" }, { - "source": "repos/pbdf-staging", - "github": "https://github.com/privacybydesign/pbdf-staging/blob/main" + "PATH": "repos/pbdf-staging", + "url": "https://github.com/privacybydesign/pbdf-staging/archive/refs/heads/master.zip" } ] \ No newline at end of file diff --git a/download_repos.py b/download_repos.py index e80b564..337e194 100644 --- a/download_repos.py +++ b/download_repos.py @@ -1,35 +1,28 @@ import os import json -import subprocess +import requests +import zipfile +import io -def clone_or_update_repo(source, github_url, base_dir="."): - """ - Clones or updates a GitHub repository based on the source and GitHub URL. +def download_and_extract_zip(url, base_dir="."): + repo_dir = os.path.join(base_dir, "repos") + os.makedirs(repo_dir, exist_ok=True) - Args: - source (str): Name of the source directory to store the repo. - github_url (str): URL of the GitHub repository. - base_dir (str): Base directory where the repos are stored. - """ - os.makedirs(base_dir, exist_ok=True) - - repo_dir = os.path.join(base_dir, source) - - if github_url.endswith("/blob/master"): - github_url = github_url.replace("/blob/master", ".git") - elif github_url.endswith("/blob/main"): - github_url = github_url.replace("/blob/main", ".git") - elif github_url.endswith("/master"): - github_url = github_url.replace("/master", ".git") - elif github_url.endswith("/main"): - github_url = github_url.replace("/main", ".git") - - if os.path.exists(repo_dir): - print(f"Updating repository: {source}") - subprocess.run(["git", "-C", repo_dir, "pull"], check=True) + response = requests.get(url) + if response.status_code == 200: + with zipfile.ZipFile(io.BytesIO(response.content)) as zip_ref: + zip_ref.extractall(repo_dir) + + # Rename directories if they end with -master or -main + for root, dirs, files in os.walk(repo_dir): + for dir_name in dirs: + if dir_name.endswith("-master") or dir_name.endswith("-main"): + new_name = dir_name.rsplit("-", 1)[0] + os.rename(os.path.join(root, dir_name), os.path.join(root, new_name)) + + print(f"Downloaded and extracted zip file to: {repo_dir}") else: - print(f"Cloning repository: {source}") - subprocess.run(["git", "clone", github_url, repo_dir], check=True) + print(f"Failed to download zip from {url}. Status code: {response.status_code}") def main(): config_file = "config.json" @@ -41,16 +34,15 @@ def main(): with open(config_file, "r") as file: config = json.load(file) - for repo in config: - source = repo.get("source") - github_url = repo.get("github") - if source and github_url: + for scheme in config: + zip_url = scheme.get("url") + if zip_url: try: - clone_or_update_repo(source, github_url) - except subprocess.CalledProcessError as e: - print(f"Error processing {source}: {e}") + download_and_extract_zip(zip_url) + except requests.RequestException as e: + print(f"Error processing {zip_url}: {e}") else: - print(f"Invalid configuration entry: {repo}") + print(f"Invalid configuration entry: {scheme}") if __name__ == "__main__": main() diff --git a/pbdf-staging b/pbdf-staging deleted file mode 160000 index a766e7b..0000000 --- a/pbdf-staging +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a766e7b087d6b598d90bb2924b8218c24f4e9af1 diff --git a/repos/pbdf-staging b/repos/pbdf-staging deleted file mode 160000 index a766e7b..0000000 --- a/repos/pbdf-staging +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a766e7b087d6b598d90bb2924b8218c24f4e9af1 diff --git a/update.py b/update.py index dc8a28c..b13c586 100755 --- a/update.py +++ b/update.py @@ -110,7 +110,7 @@ def readIssuer(path): return issuer -def readSchemeManager(path, githubURL): +def readSchemeManager(path): schememgr = {} xml = minidom.parse(path + '/description.xml') @@ -119,7 +119,6 @@ def readSchemeManager(path, githubURL): 'name': translated(xml.getElementsByTagName('Name')[0]), 'description': translated(xml.getElementsByTagName('Description')[0]), 'url': getText(xml.getElementsByTagName('Url')[0]), - 'github': githubURL, 'contact': getText(xml.getElementsByTagName('Contact')[0]), 'keyshareServer': None, 'keyshareWebsite': None, @@ -148,7 +147,6 @@ def readSchemeManager(path, githubURL): return schememgr - def generateHTML(index, out, lang): os.makedirs(out, exist_ok=True) @@ -227,7 +225,7 @@ def generateHTML(index, out, lang): try: index = [] for info in schememanagers: - index.append(readSchemeManager(info['source'], info['github'])) + index.append(readSchemeManager(info['PATH'])) with open('index.json', 'w') as json_file: json.dump(index, json_file)