# Artifactview View CI build artifacts from Forgejo/Github using your web browser. Forgejo and GitHub's CI systems allow you to upload files and directories as [artifacts](https://github.com/actions/upload-artifact). These can be downloaded as zip files. However there is no simple way to view individual files of an artifact. Artifactview is a small web application that fetches these CI artifacts and displays their contents. It offers full support for single page applications and custom 404 error pages. Single-page applications require a file named `200.html` placed in the root directory, which will be served in case no file exists for the requested path. A custom 404 error page is defined using a file named `404.html` in the root directory. Artifactview displays a file listing if there is no `index.html` or fallback page present, so you can browse artifacts that dont contain websites. ![Artifact file listing](resources/screenshotFiles.png) ## How to use Open a Github/Gitea/Forgejo actions run with artifacts and paste its URL into the input box on the main page. You can also pass the run URL with the `?url=` parameter. Artifactview will show you a selection page where you will be able to choose the artifact you want to browse. ## Setup You can run artifactview using the docker image provided under `thetadev256/artifactview:latest` or bare-metal using the provided binaries. Artifactview is designed to run behind a reverse proxy since it does not support HTTPS by itself. If you are using a reverse proxy, you have to set the `REAL_IP_HEADER` option to the client IP address header name provided by the proxy (usually `x-forwarded-for`. Otherwise artifactview will assume it is being accessed by only 1 client (the proxy itself) and the rate limiter would count all users as one. ### Docker Compose Here is an example setup with docker-compose, using Traefik as a reverse proxy: ```yaml services: artifactview: image: thetadev256/artifactview:latest restart: unless-stopped networks: - proxy environment: ROOT_DOMAIN: av.thetadev.de REAL_IP_HEADER: x-forwarded-for GITHUB_TOKEN: github_pat_123456 REPO_WHITELIST: github.com;codeberg.org;code.thetadev.de SITE_ALIASES: gh=>github.com;cb=>codeberg.org;th=>code.thetadev.de labels: - "traefik.enable=true" - "traefik.docker.network=proxy" - "traefik.http.routers.artifactview.entrypoints=websecure" - "traefik.http.routers.artifactview.rule=HostRegexp(`^[a-z0-9-]*.?av.thetadev.de$`)" networks: proxy: external: true ``` ### Configuration Artifactview is configured using environment variables. | Variable | Default | Description | | ------------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `PORT` | 3000 | HTTP port | | `CACHE_DIR` | /tmp/artifactview | Temporary directory where to store the artifacts | | `ROOT_DOMAIN` | localhost:3000 | Public hostname+port number under which artifactview is accessible. If this is configured incorrectly, artifactview will show the error message "host does not end with configured ROOT_DOMAIN" | | `RUST_LOG` | info | Logging level | | `NO_HTTPS` | false | Set to True if the website is served without HTTPS (used if testing artifactview without an ) | | `MAX_ARTIFACT_SIZE` | 100000000 (100 MB) | Maximum size of the artifact zip file to be downloaded | | `MAX_FILE_SIZE` | 100000000 (100 MB) | Maximum contained file size to be served | | `MAX_FILE_COUNT` | 10000 | Maximum amount of files within a zip file | | `MAX_AGE_H` | 12 | Maximum age in hours after which cached artifacts are deleted | | `ZIP_TIMEOUT_MS` | 1000 | Maximum time in milliseconds for reading the index of a zip file. If this takes too long, the zip file is most likely excessively large or malicious (zip bomb) | | `GITHUB_TOKEN` | - | GitHub API token for downloading artifacts. Using a fine-grained token with public read permissions is recommended | | `MEM_CACHE_SIZE` | 50 | Artifactview keeps artifact metadata as well as the zip file indexes in memory to improve performance. The amount of cached items is adjustable. | | `REAL_IP_HEADER` | - | Get the client IP address from a HTTP request header
If Artifactview is exposed to the network directly, this option has to be unset. If you are using a reverse proxy the proxy needs to be configured to send the actual client IP as a request header.
For most proxies this header is `x-forwarded-for`. | | `LIMIT_ARTIFACTS_PER_MIN` | 5 | Limit the amount of downloaded artifacts per IP address and minute | | `REPO_BLACKLIST` | - | List of sites/users/repos that can NOT be accessed. The blacklist takes precedence over the whitelist (repos included in both lists cannot be accessed)
Example: `github.com/evil-corp/world-destruction;codeberg.org/blackhat;example.org` | | `REPO_WHITELIST` | - | List of sites/users/repos that can ONLY be accessed. If the whitelist is empty, it will be ignored and any repository can be accessed. Uses the same syntax as `REPO_BLACLIST`. | | `SITE_ALIASES` | - | Aliases for sites to make URLs shorter
Example: `gh => github.com;cb => codeberg.org` | | `VIEWER_MAX_SIZE` | 500000 | Maximum file size to be displayed using the viewer | ## Technical details ### URL format Artifactview uses URLs in the given format for accessing the individual artifacts: `-------.hostname` Example: `https://github-com--theta-dev--example-project--4-11.example.com` The reason for using subdomains instead of URL paths is that many websites expect to be served from a separate subdomain and access resources using absolute paths. Using URLs like `example.com/github.com/theta-dev/example-project/4/11/path/to/file` would make the application easier to host, but it would not be possible to simply preview a React/Vue/Svelte web project. Since domains only allow letters, numbers and dashes but repository names allow dots and underscores, these escape sequences are used to access repositories with special characters in their names. - `-0` -> `.` - `-1` -> `-` - `-2` -> `_` Another issue with using subdomains is that they are limited to a maximum of 63 characters. Most user and repository names are short enough for this not to become a problem, but it could still happen that a CI run becomes inaccessible. Since the run ID is incremented on each new CI run, it might even happen that Artifactview works fine at the beginning of a project, but the subdomains exceed the length limit in the future. That's why I added aliases for forge URLs. You can for example alias github.com as gh, shaving 8 characters from the subdomain. This makes the subdomains short enogh that you will be unlikely to hit the limit even with longer user/project names. ### Security considerations It is recommended to use the whitelist feature to allow artifactview to access only trusted servers, users and organizations. Since many [well-known URIs](https://www.iana.org/assignments/well-known-uris/well-known-uris.xhtml) are used to configure security-relevant properties of a website or attest ownership of a website (like `.well-known/acme-challenge` for issuing TLS certificates), Artifactview will serve no files from the `.well-known` folder. There is a configurable limit for both the maximum downloaded artifact size and the maximum size of individual files to be served (100MB by default). Additionally there is a configurable timeout for the zip file indexing operation. These measures should protect the server againt denial-of-service attacks like overfilling the server drive or uploading zip bombs.