diff --git a/.github/cla-allowlist.txt b/.github/cla-allowlist.txt new file mode 100644 index 00000000..c3c08db3 --- /dev/null +++ b/.github/cla-allowlist.txt @@ -0,0 +1,25 @@ +# Accounts exempt from the CLA check (.github/workflows/cla.yml). +# One GitHub username per line; lines starting with # and blank lines are +# ignored. '*' wildcards are supported (e.g. bot accounts). +# +# The workflow reads this file from the default branch, so changes take +# effect once they land there — a PR cannot allowlist its own author. +# +# Bots: +dependabot[bot] +renovate[bot] + +# Tower employees: exempt because they have already signed equivalent +# agreements as part of employment; the CLA record for them lives in their +# employment paperwork, not in signatures/. Keep in sync with org +# membership; remove people when they leave (their later contributions need +# a signature like anyone else's). +bradhe +datancoffee +giray123 +jo-sm +konstantinoscs +MemoAlfa +mesmith027 +sammuti +socksy diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 00000000..184fa342 --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,102 @@ +# CLA enforcement via CLA Assistant Lite (contributor-assistant/github-action). +# +# NOTE: the upstream repository (contributor-assistant/github-action) was +# archived in March 2026 and is read-only. Existing releases keep working. +# This is deliberate: unlike the hosted cla-assistant.io app, this action +# stores signatures inside this repository, which is a hard requirement. +# Consequences: +# - The action is pinned to a commit SHA (of the last release, v2.6.1). +# - Treat it as frozen: do not add Dependabot/Renovate config for it, and +# do not expect upstream updates or fixes. +# +# Signature storage: the action writes cla.json to `develop` directly (it +# cannot open PRs), which the develop ruleset's pull-request requirement +# would normally reject — and GitHub does not allow the built-in Actions +# token to bypass rulesets. So the write goes through a dedicated org-owned +# GitHub App (Contents: read/write only): its token is minted below and +# passed as PERSONAL_ACCESS_TOKEN, which the action uses for signature +# persistence only (comments/status/lock still use GITHUB_TOKEN). The app +# must be installed on this repo and listed as a bypass actor on the develop +# ruleset, or signing fails at the moment someone signs. +# Secrets required: CLA_APP_ID, CLA_APP_PRIVATE_KEY. +# cla.json reaches main through the normal develop -> main release merges. +# +# Signature versioning: signatures are stored under signatures/version1/. +# If CLA.md is ever materially changed, bump the path to signatures/version2/ +# (and so on) so that prior signatures do not silently appear to cover text +# nobody agreed to. +name: CLA Assistant +on: + issue_comment: + types: [created] + pull_request_target: + types: [opened, closed, synchronize] + +permissions: + actions: write + contents: write + pull-requests: write + statuses: write + +jobs: + cla: + runs-on: ubuntu-latest + # The `github.event.issue.pull_request` guard is required: without it, + # comments on ordinary issues (not PRs) trigger the workflow. The upstream + # README example omits it; that is a known upstream bug. + if: > + github.event_name == 'pull_request_target' || + (github.event.issue.pull_request && + contains(fromJSON('["recheck","I have read the CLA Document and I hereby sign the CLA"]'), + github.event.comment.body)) + # One run at a time per PR: `opened` + `synchronize` arriving together + # would otherwise race on the cla.json write. + concurrency: + group: cla-${{ github.event.pull_request.number || github.event.issue.number }} + cancel-in-progress: false + steps: + # The action only accepts the allowlist as a string input, so it is + # tracked in .github/cla-allowlist.txt and loaded here. It is pinned to + # `develop` (maintainer-controlled, matches the signature branch) so a + # PR cannot allowlist its own author by editing the file, and so + # issue_comment runs — which execute from the default branch — read the + # same copy as pull_request_target runs. pipefail makes a failed fetch + # fail the job instead of silently producing an empty allowlist. + - name: Load allowlist + id: allowlist + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + list=$(gh api "repos/${{ github.repository }}/contents/.github/cla-allowlist.txt?ref=develop" --jq '.content' \ + | base64 --decode | grep -vE '^[[:space:]]*(#|$)' | paste -sd, -) + echo "list=$list" >> "$GITHUB_OUTPUT" + - name: Mint signature-write token + id: app-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + app-id: ${{ secrets.CLA_APP_ID }} + private-key: ${{ secrets.CLA_APP_PRIVATE_KEY }} + - uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1 — upstream archived 2026-03 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PERSONAL_ACCESS_TOKEN: ${{ steps.app-token.outputs.token }} + with: + path-to-signatures: 'signatures/version1/cla.json' + path-to-document: 'https://github.com/tower/tower-cli/blob/develop/CLA.md' + branch: 'develop' + # Pointing "remote" at this same repo is what routes the signature + # write through PERSONAL_ACCESS_TOKEN (the app token) instead of + # GITHUB_TOKEN — the action only uses the PAT client when a remote + # repo/org is configured. + remote-organization-name: 'tower' + remote-repository-name: 'tower-cli' + allowlist: ${{ steps.allowlist.outputs.list }} + # Without this, the action matches the sign phrase as a substring + # (regex .*phrase.*), so "... I hereby sign the CLA, but I do not + # agree" would count as a signature. Setting custom-pr-sign-comment + # switches the action to exact (trimmed, case-insensitive) matching. + custom-pr-sign-comment: 'I have read the CLA Document and I hereby sign the CLA' + # lock-on-merge is left at its default (enabled) on purpose: locking + # the PR conversation after merge is what makes the signature + # comments immutable, which is the evidentiary value of the record. diff --git a/CLA.md b/CLA.md new file mode 100644 index 00000000..75a28f49 --- /dev/null +++ b/CLA.md @@ -0,0 +1,121 @@ +# Tower Individual Contributor License Agreement + +Before your pull request can be merged, Tower asks you to sign this +contributor license agreement. Signing does not transfer ownership of your +work: you keep the copyright in your contributions and grant Tower and users +of Tower's software a license to use, modify, and distribute them. You sign +by replying to the CLA bot's comment on your pull request, and the signature +is recorded in this repository. + +--- + +Thank you for your interest in Tower Computing GmbH ("Tower"). To clarify the +intellectual property license granted with Contributions from any person or +entity, Tower must have on file a signed Contributor License Agreement +("CLA") from each Contributor, indicating agreement with the license terms +below. This agreement is for your protection as a Contributor as well as the +protection of Tower and its users. It does not change your rights to use your +own Contributions for any other purpose. + +You sign this Agreement electronically by posting the signature comment +requested by the CLA workflow on your GitHub pull request. Your GitHub +username and the metadata recorded by the workflow constitute the record of +your signature and are stored in this repository. + +You accept and agree to the following terms and conditions for Your +Contributions (present and future) that you submit to Tower. Except for the +license granted herein to Tower and recipients of software distributed by +Tower, You reserve all right, title, and interest in and to Your +Contributions. + +1. Definitions. + + "You" (or "Your") shall mean the copyright owner or legal entity + authorized by the copyright owner that is making this Agreement with + Tower. For legal entities, the entity making a Contribution and all other + entities that control, are controlled by, or are under common control with + that entity are considered to be a single Contributor. For the purposes of + this definition, "control" means (i) the power, direct or indirect, to + cause the direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "Contribution" shall mean any original work of authorship, including any + modifications or additions to an existing work, that is intentionally + submitted by You to Tower for inclusion in, or documentation of, any of + the products owned or managed by Tower (the "Work"). For the purposes of + this definition, "submitted" means any form of electronic, verbal, or + written communication sent to Tower or its representatives, including but + not limited to communication on electronic mailing lists, source code + control systems, and issue tracking systems that are managed by, or on + behalf of, Tower for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by You as "Not a Contribution." + +2. Grant of Copyright License. Subject to the terms and conditions of this + Agreement, You hereby grant to Tower and to recipients of software + distributed by Tower a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable copyright license to reproduce, prepare + derivative works of, publicly display, publicly perform, sublicense, and + distribute Your Contributions and such derivative works. + +3. Grant of Patent License. Subject to the terms and conditions of this + Agreement, You hereby grant to Tower and to recipients of software + distributed by Tower a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable (except as stated in this section) patent + license to make, have made, use, offer to sell, sell, import, and + otherwise transfer the Work, where such license applies only to those + patent claims licensable by You that are necessarily infringed by Your + Contribution(s) alone or by combination of Your Contribution(s) with the + Work to which such Contribution(s) was submitted. If any entity institutes + patent litigation against You or any other entity (including a cross-claim + or counterclaim in a lawsuit) alleging that your Contribution, or the Work + to which you have contributed, constitutes direct or contributory patent + infringement, then any patent licenses granted to that entity under this + Agreement for that Contribution or Work shall terminate as of the date + such litigation is filed. + +4. You represent that you are legally entitled to grant the above license. + If your employer(s) has rights to intellectual property that you create + that includes your Contributions, you represent that you have received + permission to make Contributions on behalf of that employer, that your + employer has waived such rights for your Contributions to Tower, or that + your employer has executed a separate Corporate CLA with Tower. + +5. You represent that each of Your Contributions is Your original creation + (see section 7 for submissions on behalf of others). You represent that + Your Contribution submissions include complete details of any third-party + license or other restriction (including, but not limited to, related + patents and trademarks) of which you are personally aware and which are + associated with any part of Your Contributions. + +6. You are not expected to provide support for Your Contributions, except to + the extent You desire to provide support. You may provide support for + free, for a fee, or not at all. Unless required by applicable law or + agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + including, without limitation, any warranties or conditions of TITLE, + NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + +7. Should You wish to submit work that is not Your original creation, You + may submit it to Tower separately from any Contribution, identifying the + complete details of its source and of any license or other restriction + (including, but not limited to, related patents, trademarks, and license + agreements) of which you are personally aware, and conspicuously marking + the work as "Submitted on behalf of a third-party: [named here]". + +8. You agree to notify Tower of any facts or circumstances of which you + become aware that would make these representations inaccurate in any + respect. + +9. Prior Contributions. This Agreement applies to all Contributions You + submitted to Tower before the date You sign this Agreement, as well as to + all Contributions You submit on or after that date. The licenses granted + in sections 2 and 3, and the representations made in sections 4, 5, 7, + and 8, apply equally to such prior Contributions. + +10. Governing Law. This Agreement shall be governed by and construed in + accordance with the laws of the Federal Republic of Germany, without + regard to its conflict of laws principles. Any dispute arising out of or + relating to this Agreement shall be subject to the exclusive jurisdiction + of the courts at the registered seat of Tower Computing GmbH in Germany. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 12749ce9..51c5a1d7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,6 +27,14 @@ If you still need help: > **Legal Notice:** When contributing, you must agree that you have authored 100% of the content, have the necessary rights, and that it may be provided under the project license. +### Contributor License Agreement + +A signed [Contributor License Agreement](CLA.md) is required before any pull request can be merged. + +Signing happens on the pull request itself: when you open a PR, a bot comments with a link to the CLA and a required status check fails. Reply to the bot's comment with the exact phrase it asks for (`I have read the CLA Document and I hereby sign the CLA`) and the check clears. You only need to do this once; it covers your future pull requests too. + +If you can't sign on your own behalf — for example, because your employer holds rights in your work — please say so before submitting a pull request. + ### Reporting Bugs #### Before Submitting diff --git a/LICENSE b/LICENSE index 34da8d48..486f8251 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Tower Computing Inc. +Copyright (c) 2024 Tower Computing GmbH Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/flake.nix b/flake.nix index 29ab86e4..14937be2 100644 --- a/flake.nix +++ b/flake.nix @@ -22,7 +22,7 @@ overlays = [ rust-overlay.overlays.default ]; }; - maintainer = "Tower Computing Inc. "; + maintainer = "Tower Computing GmbH "; homepage = "https://github.com/tower/tower-cli"; description = "Tower CLI and runtime environment"; longDescription = " | @@ -47,7 +47,7 @@ ${if packager == "rpm" then "release: 1" else "section: utils\npriority: optional"} maintainer: ${maintainer} description: ${longDescription} - vendor: Tower Computing Inc. + vendor: Tower Computing GmbH homepage: "${homepage}" license: MIT diff --git a/pyproject.toml b/pyproject.toml index 8d84c009..72825624 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "maturin" name = "tower" version = "0.3.70" description = "Tower CLI and runtime environment for Tower." -authors = [{ name = "Tower Computing Inc.", email = "brad@tower.dev" }] +authors = [{ name = "Tower Computing GmbH", email = "brad@tower.dev" }] readme = "README.md" requires-python = ">=3.12" license = { file = "LICENSE" }