diff --git a/.github/workflows/reuse-lint.yml b/.github/workflows/reuse-lint.yml index 95b7a158f..7d4402d62 100644 --- a/.github/workflows/reuse-lint.yml +++ b/.github/workflows/reuse-lint.yml @@ -82,7 +82,7 @@ jobs: fi echo "OK: CONTRIBUTING.md references DCO / sign-off" - # Inline SPDX-License-Identifier on first-party source files. + # Inline SPDX copyright and license tags on first-party source files. # REUSE.toml provides aggregate coverage so 'reuse lint' is green even # without inline headers, but inline tags are the OSRB-preferred form # and catch new files copied in without attribution. @@ -95,13 +95,24 @@ jobs: set -euo pipefail excludes='^integrations/omnidreams/ludus-renderer/ludus_renderer/_cpp/cudaraster/' excludes+='|^integrations/omnidreams/omnidreams/grpc/protos/.*_pb2' - missing_files=() + missing_copyright_files=() + missing_license_files=() + # Anchor tags to supported source-comment syntax so strings and + # docstrings containing SPDX-like text do not satisfy the policy. + # REUSE-IgnoreStart + copyright_pattern='^[[:space:]]*(#|//|/\*|\*)[[:space:]]*SPDX-FileCopyrightText:[[:space:]]*[^[:space:]]' + license_pattern='^[[:space:]]*(#|//|/\*|\*)[[:space:]]*SPDX-License-Identifier:[[:space:]]*[^[:space:]]' + # REUSE-IgnoreEnd while IFS= read -r f; do if printf '%s\n' "$f" | grep -qE "$excludes"; then continue fi - if ! head -n 20 "$f" | grep -q "SPDX-License-Identifier"; then - missing_files+=("$f") + header=$(head -n 20 "$f") + if ! printf '%s\n' "$header" | grep -qE "$copyright_pattern"; then + missing_copyright_files+=("$f") + fi + if ! printf '%s\n' "$header" | grep -qE "$license_pattern"; then + missing_license_files+=("$f") fi done < <(git ls-files \ '*.py' '*.pyx' '*.pyi' \ @@ -110,17 +121,28 @@ jobs: '*.cu' '*.cuh' '*.inl' \ '*.sh' '*.proto' \ 'Dockerfile' '*/Dockerfile' '**/Dockerfile' '*.dockerfile') - if [ "${#missing_files[@]}" -gt 0 ]; then + if [ "${#missing_copyright_files[@]}" -gt 0 ] || [ "${#missing_license_files[@]}" -gt 0 ]; then # Print the list to the raw log so it shows in the step output, # then emit GitHub annotations so the offending files appear in # the PR "Files changed" review tab too. - echo - echo "The following ${#missing_files[@]} source file(s) are missing an" - echo "inline 'SPDX-License-Identifier' tag in their first 20 lines:" - echo - for f in "${missing_files[@]}"; do - echo " - $f" - done + if [ "${#missing_copyright_files[@]}" -gt 0 ]; then + echo + echo "The following ${#missing_copyright_files[@]} source file(s) are missing a non-empty" + echo "inline 'SPDX-FileCopyrightText' tag in their first 20 lines:" + echo + for f in "${missing_copyright_files[@]}"; do + echo " - $f" + done + fi + if [ "${#missing_license_files[@]}" -gt 0 ]; then + echo + echo "The following ${#missing_license_files[@]} source file(s) are missing a non-empty" + echo "inline 'SPDX-License-Identifier' tag in their first 20 lines:" + echo + for f in "${missing_license_files[@]}"; do + echo " - $f" + done + fi echo # REUSE-IgnoreStart echo "Add a header like (Python/shell comment style):" @@ -128,14 +150,17 @@ jobs: echo " # SPDX-License-Identifier: Apache-2.0" echo "C/C++/CUDA files use '//' line comments with the same two tags." echo - for f in "${missing_files[@]}"; do - echo "::error file=$f,line=1,title=Missing SPDX header::Add 'SPDX-License-Identifier: Apache-2.0' (and matching SPDX-FileCopyrightText) to the first 20 lines of this file." + for f in "${missing_copyright_files[@]}"; do + echo "::error file=$f,line=1,title=Missing SPDX copyright::Add a non-empty 'SPDX-FileCopyrightText' tag to the first 20 lines of this file." + done + for f in "${missing_license_files[@]}"; do + echo "::error file=$f,line=1,title=Missing SPDX license::Add a non-empty 'SPDX-License-Identifier' tag to the first 20 lines of this file." done # REUSE-IgnoreEnd - echo "::error title=Missing SPDX headers::${#missing_files[@]} source file(s) missing inline SPDX header" + echo "::error title=Missing SPDX headers::${#missing_copyright_files[@]} source file(s) missing copyright tags; ${#missing_license_files[@]} missing license tags" exit 1 fi - echo "OK: every tracked source file carries an inline SPDX-License-Identifier" + echo "OK: every tracked source file carries inline SPDX copyright and license tags" - name: No NVIDIA proprietary banners run: | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9f8bc615d..41459b675 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -235,29 +235,19 @@ short ping comment. - Tests live in `flashdreams/tests/` and `integrations/*/tests/`. Use `pytest` and prefer existing fixtures over hand-rolled setup. See [Testing](#testing) for marker requirements. -- Every source file added by a contribution must include the SPDX - header used elsewhere in the project: +- Every source file added by a contribution must include this concise + two-line SPDX header: ```python - # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + # SPDX-FileCopyrightText: Copyright (c) # SPDX-License-Identifier: Apache-2.0 - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. ``` - External contributors should add their own copyright line *above* the - NVIDIA line if they wish to be attributed; both attributions are - retained. + Use the current calendar year and the name of the actual copyright + holder, which may be the contributor, their organization, or NVIDIA. + Preserve existing copyright notices when modifying a file; multiple + `SPDX-FileCopyrightText` lines are allowed. The longer Apache-2.0 + boilerplate is accepted but not required. ## Testing diff --git a/skills/maintaining-oss-state/SKILL.md b/skills/maintaining-oss-state/SKILL.md index f498f0a61..aca8333f5 100644 --- a/skills/maintaining-oss-state/SKILL.md +++ b/skills/maintaining-oss-state/SKILL.md @@ -45,7 +45,7 @@ gates catch what. can't carry one (config, assets, binaries), but `reuse-lint`'s "Inline SPDX headers on first-party source files" step rejects any new `.py` / `.c` / `.cpp` / `.cu` / `.sh` / `.proto` / `Dockerfile` - / etc. without the inline tag. + / etc. without both non-empty inline tags. - **Direct deps are mirrored in three places:** the workspace member's `pyproject.toml` `dependencies`, the resolved `uv.lock` pin, and the `THIRD-PARTY-NOTICES` "Direct runtime dependencies" table. All @@ -82,32 +82,26 @@ fix the underlying file. ## 2. Per-file SPDX headers -Every first-party source file starts with the inline SPDX header. The -exact wording is enforced by `reuse-lint`'s "Inline SPDX headers on -first-party source files" step (looks for `SPDX-License-Identifier` in -the first 20 lines). +Every first-party source file starts with an inline SPDX header. The +`reuse-lint` "Inline SPDX headers on first-party source files" step +requires non-empty `SPDX-FileCopyrightText` and +`SPDX-License-Identifier` tags on `#`, `//`, or block-comment `*` +lines in the first 20 lines. Anchoring the tags to comment syntax +prevents SPDX-like text in strings or docstrings from satisfying the +policy. The check +deliberately does not prescribe the copyright holder text: public +contributors may use their own notice, and a file may carry multiple +copyright notices. **Python / shell / TOML / YAML** (`#` line comments): ```python # SPDX-FileCopyrightText: Copyright (c) NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. ``` -**C / C++ / CUDA** (`//` line comments): same two SPDX tags + the same -Apache-2.0 preamble, with `//` swapped for `#`. +**C / C++ / CUDA**: the same two SPDX tags on `//` lines or on `*` +lines within a `/* ... */` block comment. Rules: @@ -116,12 +110,13 @@ Rules: files being **edited**, leave the year alone — it reflects original authorship, not last-touched. - The two SPDX tags (`SPDX-FileCopyrightText` + `SPDX-License-Identifier`) - are the load-bearing part. The Apache-2.0 preamble is house style; - the CI gate only checks for `SPDX-License-Identifier` in the first 20 - lines, but the long form is what every existing file carries, so - match it. -- External contributors add their **own** copyright line *above* the - NVIDIA line — keep both. See `CONTRIBUTING.md:200-235`. + are the complete, preferred header: concise, standardized, and + machine-verifiable. The longer Apache-2.0 boilerplate is accepted but + not required. +- External contributors may use their **own** copyright notice. When + modifying an existing file, preserve all existing notices and add the + contributor's notice as another `SPDX-FileCopyrightText` line. See + the "Coding conventions" section of `CONTRIBUTING.md`. - The Cosmos-Drive-Dreams files (`integrations/omnidreams/omnidreams/conditioning/world_scenario/{camera_base,ftheta,pinhole}.py`) carry two `SPDX-FileCopyrightText` lines (NVIDIA + Cosmos-Drive-Dreams @@ -440,9 +435,10 @@ When extending CONTRIBUTING.md: - Keep the DCO section anchored at `## Developer Certificate of Origin (DCO)` — the README and external docs link to it by anchor. -- The SPDX header preamble at `CONTRIBUTING.md:200-235` doubles as the - agent-and-human source for what every new source file's header should - look like. Update it and `python-docstring-style/SKILL.md` together. +- The SPDX header example in `CONTRIBUTING.md`'s "Coding conventions" + section doubles as the agent-and-human source for what every new + source file's header should look like. Update it and + `python-docstring-style/SKILL.md` together. - The IP-review-process reference in `CONTRIBUTING.md` is an OSRB pointer — don't change it without OSRB sign-off. @@ -484,9 +480,11 @@ sections). 4. Every tracked source file (`.py`, `.pyx`, `.pyi`, `.c`, `.cc`, `.cpp`, `.cxx`, `.h`, `.hh`, `.hpp`, `.hxx`, `.cu`, `.cuh`, `.inl`, `.sh`, `.proto`, `Dockerfile` / `*.dockerfile`) carries - an inline `SPDX-License-Identifier` in its first 20 lines — with - the documented exclusions (`cudaraster/**`, generated protobuf - stubs). + non-empty inline `SPDX-FileCopyrightText` and + `SPDX-License-Identifier` tags on `#`, `//`, or block-comment `*` + lines in its first 20 lines — with the documented exclusions + (`cudaraster/**`, + generated protobuf stubs). 5. No file contains the legacy NVIDIA proprietary-banner sentinel phrases checked by `.github/workflows/reuse-lint.yml`. @@ -621,7 +619,7 @@ weak-copyleft):** |---|---| | What's the canonical Apache-2.0 text? | `LICENSE` (= `LICENSES/Apache-2.0.txt`) | | What deps does FlashDreams ship? | `THIRD-PARTY-NOTICES` "Direct runtime dependencies" + `flashdreams/pyproject.toml` | -| What does a SPDX header look like? | `CONTRIBUTING.md:215-232` | +| What does a SPDX header look like? | `CONTRIBUTING.md` "Coding conventions" | | Where do I declare a config / asset file's license? | `REUSE.toml` | | Where do I record vendored upstream source? | NOTICE "Source-level redistributions" + `REUSE.toml` `override` block | | What does the CI gate enforce? | `.github/workflows/reuse-lint.yml` (read top to bottom) | diff --git a/skills/python-docstring-style/SKILL.md b/skills/python-docstring-style/SKILL.md index 6b7397d61..fb8151f70 100644 --- a/skills/python-docstring-style/SKILL.md +++ b/skills/python-docstring-style/SKILL.md @@ -9,27 +9,23 @@ House style distilled from `flashdreams/`. Match it when adding or editing Pytho ## File header -Every `.py` file starts with the SPDX + Apache-2.0 block, then a blank line, then the module docstring, then a blank line, then imports. +Every `.py` file starts with the concise two-line SPDX header, then a +blank line, then the module docstring, then a blank line, then imports. ```python -# SPDX-FileCopyrightText: Copyright (c) NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) # SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. """Block KV cache for causal attention with a fixed-size local window.""" ``` +`` is the person or organization that owns the +contribution. For NVIDIA-authored files, use `NVIDIA CORPORATION & +AFFILIATES. All rights reserved.`; public contributors may use their own +name or organization. Preserve all existing notices when editing a file; +multiple `SPDX-FileCopyrightText` lines are allowed. The longer +Apache-2.0 boilerplate is accepted but not required. + **`` is the *current* calendar year, not a hardcoded literal.** Before stamping the header into a brand-new file, look up today's date (the agent host's clock, the system context, or `date +%Y` in a shell) and substitute it. The conversation's training-cutoff year is *not* the source of truth — emit e.g. `Copyright (c) 2027 …` if the file is being created in 2027. When **editing an existing file**, leave the existing year alone — the SPDX year reflects when the file was first authored, not when it was last touched. Only update the year if the file genuinely had no header before, or you're explicitly asked to refresh copyright years across the tree.