diff --git a/.circleci/config.yml b/.circleci/config.yml
index 9cd2b20cbaae07e50e7cea351c05ed72183d46b4..ae156c793dd77f514f21c158fbb99b409bb8ff92 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -53,7 +53,6 @@ jobs:
       - image: "nixorg/nix:circleci"
 
     environment:
-      CODECOV_TOKEN: "cc6e4697-4337-4506-88af-92b8f8ca6b22"
       # Specify a revision of NixOS/nixpkgs to run against.  This essentially
       # pins the majority of the software involved in the build.  This
       # revision is selected arbitrarily.  It's somewhat current as of the
@@ -144,7 +143,7 @@ jobs:
       - run:
           name: "Report Coverage"
           command: |
-            nix-shell -p 'python.withPackages (ps: [ ps.codecov ])' --keep CODECOV_TOKEN --run \
+            nix-shell -p 'python.withPackages (ps: [ ps.codecov ])' --run \
               'codecov --file ./result-doc/share/doc/*/.coverage'
 
 workflows:
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000000000000000000000000000000000000..ec19cb88f397c327bac1afa6a195073f305e3e3d
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,6 @@
+[run]
+source =
+    _zkapauthorizer
+    twisted.plugins.zkapauthorizer
+
+branch = True
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..14597dfa154408575b6e5d80d202c4e70d556c25
--- /dev/null
+++ b/.github/workflows/ci.yaml
@@ -0,0 +1,44 @@
+name: "ci"
+
+on:
+  - "push"
+
+jobs:
+  unit-tests:
+    runs-on: "windows-latest"
+    strategy:
+      matrix:
+        python-version:
+          - "2.7"
+
+    steps:
+    - uses: actions/checkout@v2
+      with:
+        fetch-depth: "0"
+    # Get tags not fetched by the checkout action, needed for auto-versioning.
+    - run: "git fetch origin +refs/tags/*:refs/tags/*"
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v1
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        pip install wheel tox
+    - name: Get Tahoe-LAFS master
+      run: |
+        pip wheel --wheel-dir ./wheelhouse git+https://github.com/tahoe-lafs/tahoe-lafs@master#egg=tahoe-lafs
+    - name: "Install Dependencies"
+      run: |
+        PIP_FIND_LINKS=./wheelhouse python -m pip install ./
+
+    - name: "Run Tests"
+      env:
+        MAGIC_FOLDER_HYPOTHESIS_PROFILE: "ci"
+      run: |
+        python -m coverage run -m twisted.trial _zkapauthorizer
+        coverage xml
+
+    - uses: codecov/codecov-action@v1
+      with:
+        file: "./coverage.xml"
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 0000000000000000000000000000000000000000..40b059fae03e3f7df4c945b9c5ceb9e5983b1d08
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,2 @@
+codecov:
+  token: "cc6e4697-4337-4506-88af-92b8f8ca6b22"