{"id":44677319,"url":"https://github.com/specify/specify7-test-panel","last_synced_at":"2026-02-15T03:30:38.351Z","repository":{"id":32114341,"uuid":"35686755","full_name":"specify/specify7-test-panel","owner":"specify","description":"A cluster of Specify 7 instances with automatic deployment, authentication and a test panel for setting configuration","archived":false,"fork":false,"pushed_at":"2025-08-22T20:41:18.000Z","size":8966,"stargazers_count":0,"open_issues_count":49,"forks_count":1,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-08-22T22:54:56.109Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://max.patii.uk/projects/specify7-test-panel","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/specify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-05-15T17:18:03.000Z","updated_at":"2025-07-21T20:37:19.000Z","dependencies_parsed_at":"2024-02-07T02:26:31.160Z","dependency_job_id":"0146e5fb-a06e-41a6-ae39-11b68cae72ba","html_url":"https://github.com/specify/specify7-test-panel","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/specify/specify7-test-panel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/specify%2Fspecify7-test-panel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/specify%2Fspecify7-test-panel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/specify%2Fspecify7-test-panel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/specify%2Fspecify7-test-panel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/specify","download_url":"https://codeload.github.com/specify/specify7-test-panel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/specify%2Fspecify7-test-panel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29466929,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T01:01:38.065Z","status":"online","status_checked_at":"2026-02-15T02:00:07.449Z","response_time":118,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-15T03:30:36.523Z","updated_at":"2026-02-15T03:30:38.346Z","avatar_url":"https://github.com/specify.png","language":"TypeScript","funding_links":[],"categories":["Repositories"],"sub_categories":[],"readme":"# Specify 7 Test Panel\n\nA cluster of Specify 7 instances for testing with automatic deployment,\nauthentication and a test panel for setting configuration.\n\nThese instructions have last been updated and tested on Ubuntu 24.04 with MariaDB 11.4 and Docker 27.1.2. \n\n![Main Page](./docs/src/main-page.png)\n\n## Generate SSL certificates\n\nTo run the containers, generate `fullchain.pem` and `privkey.pem` (certificate\nand the private key) using Let's Encrypt and put these files into the\n`./config/` directory.\n\nWhile in development, you can generate self-signed certificates:\n\n```zsh\nopenssl req \\\n  -x509 -sha256 -nodes -newkey rsa:2048 -days 365 \\\n  -keyout ./config/privkey.pem \\\n  -out ./config/fullchain.pem\n```\n\nNote, production deployment expects `privkey.pem` and `fullchain.pem` to be in\nthe `/etc/letsencrypt/live/test.specifysystems.org-0001` directory\n\n## Create a GitHub OAuth App\n\nIn order to enable authentication though GitHub and usage of GitHub APIs, a\nGitHub OAuth application needs to be created.\n\nThis can be done for a GitHub organization or user profile:\n\n1. Open organization / user settings on GitHub\n1. On the sidebar, select \"Developer Settings\"\n1. Select \"OAuth Apps\"\n1. Press \"New OAuth App\"\n1. Fill out the required information\n1. Set authentication callback URL to this URL:\n\n   ```\n   https://localhost/sign-in\n   ```\n\n   When in production, replace `localhost` with the actual hostname\n\n1. Press \"Generate a new client secret\"\n1. Client ID and Client Secret is displayed on the OAUth app configuration page.\n1. Write them down somewhere temporary as they would be needed later\n\n## Configure automatic deployment\n\nMost GitHub API calls would be made using the token generated when the user\nauthenticates into the system.\n\nThe only exception is the webhook endpoint (`/api/webhook`), which would be\ncalled by GitHub whenever the list pull requests that are ready for testing.\n\nThis endpoint is responsible for checking getting rid of stale instances and\nauto deploying new pull requests whenever they become ready for testing.\n\n### Creating Authentication Token\n\nTo configure this, first, create personal authentication token:\n\n1. Open your GitHub's profile settings\n1. Select \"Developer Settings\" on the sidebar\n1. Select \"Personal access tokens\" on the next sidebar\n1. Press \"Generate new token\"\n1. Fill out name and expiration date as appropriate\n1. Check the `read:org` checkbox in the \"Select Scopes\" section\n1. Press \"Generate token\"\n1. Write down the generated token temporarily as it would be needed in the next\n   step\n\n### Configuring webhook\n\nNext, let's setup the webhook:\n\n1. Open the repository settings page\n1. Select \"Webhooks\" on the sidebar\n1. Press \"Add webhook\"\n1. Set `https://test.specifysolutions.com/api/webhook` as the payload URL.\n   Replace the domain name and the protocol with the one you are using.\n\n   ```\n   NOTE:\n   In order for webhook to work, this domain has to be\n   publicly accessible on the internet.\n\n   If you need to test webhooks on your local machine,\n   Google how to expose localhost\n   ```\n\n1. Change \"Content type\" picklist to `application/json`\n1. Select the \"Let me select individual events.\" radio button.\n1. Check the following checkboxes:\n\n   - Pull request review comments\n   - Pull request review threads\n   - Pull request reviews\n   - Pull requests\n   - Workflow jobs\n\n1. Click the \"Add webhook\" button\n\n## Configure Next.JS\n\nCreate `.env.local` file in the `app` folder:\n\n```ini\nNEXT_PUBLIC_GITHUB_CLIENT_ID=\u003cclient_id\u003e\nGITHUB_CLIENT_SECRET=\u003cclient_secret\u003e\n\nGITHUB_PERSONAL_TOKEN=\u003cgithub_token\u003e\n\nMYSQL_USERNAME=root\nMYSQL_PASSWORD=root\nMYSQL_HOST=mariadb\n\nREPORT_RUNNER_HOST=10.0.0.0\nREPORT_RUNNER_PORT=8080\n\nASSET_SERVER_URL=https://example.specifycloud.org/web_asset_store.xml\nASSET_SERVER_KEY=e648910c-3d2c-47b0-8f1b-fa54ac15b7b4\n```\n\nReplace `\u003cclient_id\u003e` and `\u003cclient_secret\u003e` with the actual values from the\nOAuth app configuration page on GitHub\n([see more details](#create-a-github-oauth-app))\n\nReplace `\u003cgithub_token\u003e` with the token you generated in\n[the previous step](#configure-automatic-deployment)\n\n## Setup cleanup cron job\n\nTo avoid memory leaks, setup a cron job that runs `docker system prune --all` at\na regular schedule (i.e at 3am every day).\n[Example tutorial](https://www.digitalocean.com/community/tutorials/how-to-use-cron-to-automate-tasks-ubuntu-1804)\n\nOpen the cron file:\n\n```sh\ncrontab -e\n```\n\nAdd this line:\n\n```sh\n0 3 * * * docker system prune --all --volumes --force\n```\n\n## Deployment\n\nAfter completing all the steps from previous sections, do one of these:\n\n### Production\n\nOn the host, you need to change directory access to ensure Docker logs are readable:\n```shell\nsudo chown -R 1000:988 /var/lib/docker/containers\nsudo chmod -R g+r /var/lib/docker/containers\n```\n\nBuild the containers:\n\n```shell\ndocker compose \\\n  -f docker-compose.yml \\\n  -f docker-compose.production.yml \\\n  up --no-start --build\n```\n\nRun the containers:\n\n```zsh\ndocker compose \\\n  -f docker-compose.yml \\\n  -f docker-compose.production.yml \\\n  -f /var/lib/docker/volumes/specify7-test-panel_state/_data/docker-compose.yml \\\n  up --remove-orphans -d\n```\n\nIf `/var/lib/docker/volumes/specify7-test-panel_state/_data/docker-compose.yml`\nis not correct on your host, you can find the correct path using\n`docker volume ls` and `docker volume inspect`.\n\nTest Panel is now available at [https://localhost/](https://localhost/)\n\n### Development\n\nInstall npm dependencies locally (in the `/app` directory):\n\n```zsh\nnpm i\n```\n\nBack in the main project directory, run the containers:\n\n```zsh\ndocker compose \\\n  -f docker-compose.yml \\\n  -f docker-compose.development.yml \\\n  -f state/docker-compose.yml \\\n  up --remove-orphans\n```\n\n\u003e This will deploy the development server and the deployments configured in the\n\u003e test panel. If there is no need to start the configured deployments, omit the\n\u003e `-f state/docker-compose.yml \\ ` line from above.\n\u003e\n\u003e If deployments, are not started, there would be a lot of errors in the dev\n\u003e console in the test panel. You can silence those by disabling deployment\n\u003e status fetching by adding \"?no-fetch\" to the url (https://localhost/?no-fetch)\n\nTest Panel is now available at [https://localhost/](https://localhost/)\n\nNext.JS has hot-reload enabled, so code changes are reflected in realtime.\n\nBefore committing changes, run `npm run test` to verify validity of TypeScript\ntypes.\n\n## Watch for configuration file changes\n\n### Using systemd\n\nAfter user changes the configuration in the panel, the file\n`/var/lib/docker/volumes/specify7-test-panel_state/_data/docker-compose.yml` is\nmodified. Systemd can be configured to watch this file and run docker-compose\npull and up when changes occur. Use the following unit files:\n\n#### /etc/systemd/system/specify7-test-panel-update.service\n\n```\n[Unit]\nAfter=network.target\nDescription=Run docker-compose up for test panel.\n\n[Service]\nType=oneshot\nWorkingDirectory=/home/specify/specify7-test-panel\nExecStart=docker compose -f docker-compose.yml -f docker-compose.production.yml -f /var/lib/docker/volumes/specify7-test-panel_state/_data/docker-compose.yml up --remove-orphans -d\n```\n\n#### /etc/systemd/system/specify7-test-panel-update.path\n\n```\n[Unit]\n\n[Path]\nPathChanged=/var/lib/docker/volumes/specify7-test-panel_state/_data/docker-compose.yml\nUnit=specify7-test-panel-update.service\n\n[Install]\nWantedBy=multi-user.target\n```\n\nEnable the services with the following commands:\n\n```\nsystemctl daemon-reload\nsystemctl enable specify7-test-panel-update.path\nsystemctl start specify7-test-panel-update.path\n```\n\n### Using fswatch\n\nAfter user changes the configuration in the panel, `./state/docker-compose.yml`\nfile is modified.\n\n`fswatch` can be used to rerun `docker-compose up` on configuration changes.\n\nInstall `fswatch`:\n\n```bash\n# on Ubuntu\nsudo apt-get install fswatch\n# on macOS\nbrew install fswatch\n```\n\nThen, run this command though nohup:\n\n```bash\nfswatch -o ./state/docker-compose.yml | xargs -n1 -I{} sh -c \" \\\ndocker-compose \\\n  -f docker-compose.yml \\\n  -f docker-compose.production.yml \\\n  -f state/docker-compose.yml \\\n  up --remove-orphans -d\"\n```\n\n## Miscellaneous\n\n### Initial State\n\nThe `./state` directory is indexed by git, but changes are ignored\n\nThis was achieved like this:\n\n1. Add `./state/` directory with initial content to git and commit changes\n1. Add `./state/` folder to `.gitignore`\n1. Run `git update-index --assume-unchanged state/docker-compose.yml` (do this\n   for each file in that directory)\n\nIn the future, if you want to change the default `./state/`, run this (for each\nfile):\n\n```\ngit update-index --no-assume-unchanged state/docker-compose.yml\n```\n\nThen, commit your changes and repeat step 3\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspecify%2Fspecify7-test-panel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspecify%2Fspecify7-test-panel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspecify%2Fspecify7-test-panel/lists"}