From 3b2f19d6c30266600cd219efefb108850c97d9f5 Mon Sep 17 00:00:00 2001 From: Yasunobu <42543015+P4suta@users.noreply.github.com> Date: Mon, 3 Aug 2026 20:39:58 +0900 Subject: [PATCH 1/2] ci: add licensing, spelling, and unsafe-documentation gates Closes the two baseline gaps that separated this repository from its siblings, both of which turned up real findings. Licensing and spelling: - Add REUSE.toml and LICENSES/, reaching REUSE 3.3 compliance at 58/58 files. This was the only one of the four Windows crates with no REUSE metadata at all. Annotations are path-based rather than per-file SPDX headers, matching windows-spawn, so no source file needed touching. - Add _typos.toml and run both tools in a new required CI job. The spell-check found one real misspelling in a CI helper test label. - Ship REUSE.toml and LICENSES/ in the package, as the siblings do. Unsafe documentation: - Deny clippy::undocumented_unsafe_blocks workspace-wide. CONTRIBUTING already required a specific safety justification on every unsafe block and ADR 0003 confines unsafe to src/sys.rs, but nothing checked it. - Fifteen blocks had no justification. Two were production code (RmCancelCurrentTask and RmEndSession, where the argument is that the `ended` guard serializes the call and keeps the session alive). The other thirteen were the hardening tests that deliberately fabricate malformed RM_FILTER_INFO records with out-of-bounds and misaligned pointers -- precisely where the invariants most needed writing down. Co-Authored-By: Claude Fable 5 --- .../test-dependabot-auto-merge-policy.sh | 2 +- .github/workflows/ci.yml | 12 ++ CHANGELOG.md | 8 + Cargo.toml | 11 + LICENSES/Apache-2.0.txt | 201 ++++++++++++++++++ LICENSES/CC0-1.0.txt | 121 +++++++++++ LICENSES/MIT.txt | 21 ++ REUSE.toml | 49 +++++ _typos.toml | 6 + src/sys.rs | 45 +++- xtask/Cargo.toml | 3 + 11 files changed, 476 insertions(+), 3 deletions(-) create mode 100644 LICENSES/Apache-2.0.txt create mode 100644 LICENSES/CC0-1.0.txt create mode 100644 LICENSES/MIT.txt create mode 100644 REUSE.toml create mode 100644 _typos.toml diff --git a/.github/scripts/test-dependabot-auto-merge-policy.sh b/.github/scripts/test-dependabot-auto-merge-policy.sh index 9eb7c0c..1c2e40c 100644 --- a/.github/scripts/test-dependabot-auto-merge-policy.sh +++ b/.github/scripts/test-dependabot-auto-merge-policy.sh @@ -51,7 +51,7 @@ expect false "GitHub Actions 0.x patch" "$( expect false "major update" "$(update cargo version-update:semver-major 1.2.3 false)" expect false "same-version or digest update" "$(update github-actions '' v6.0.0 false)" expect false "maintainer changes" "$(update cargo version-update:semver-patch 1.2.3 true)" -expect false "unparseable Cargo version" "$(update cargo version-update:semver-minor main false)" +expect false "unparsable Cargo version" "$(update cargo version-update:semver-minor main false)" expect false "unknown ecosystem" "$(update npm version-update:semver-patch 1.2.3 false)" expect false "credential-bearing Action" "$( update github-actions version-update:semver-patch v3.2.0 false actions/create-github-app-token diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f71e8b..7254075 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,16 @@ jobs: shell: pwsh run: ./.github/scripts/test-package-consumer.ps1 + licensing: + name: Licensing and spelling + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: fsfe/reuse-action@676e2d560c9a403aa252096d99fcab3e1132b0f5 # v6.0.0 + - uses: crate-ci/typos@bee27e3a4fd1ea2111cf90ab89cd076c870fce14 # v1.48.0 + windows-quality: name: Windows 2022 quality, native, and E2E runs-on: windows-2022 @@ -269,6 +279,7 @@ jobs: if: always() needs: - workflow-quality + - licensing - windows-quality - windows-latest - msrv @@ -284,6 +295,7 @@ jobs: - name: Reject an unsuccessful or missing CI result if: >- needs.workflow-quality.result != 'success' || + needs.licensing.result != 'success' || needs.windows-quality.result != 'success' || needs.windows-latest.result != 'success' || needs.msrv.result != 'success' || diff --git a/CHANGELOG.md b/CHANGELOG.md index 56faa6d..2a30ee1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,14 @@ All notable changes are recorded here. - Allocation-free OS-string validation, single-pass safe-layer path normalization, and malformed classification for invalid OS filter data. - Concrete example and xtask error enums without boxed error values. +- REUSE 3.3 licensing metadata (`REUSE.toml` and `LICENSES/`), a `_typos.toml`, + and a CI job that enforces both. Licensing and spelling were the two baseline + gates the sibling Windows crates had and this one did not. +- `clippy::undocumented_unsafe_blocks` is denied workspace-wide, so + CONTRIBUTING's "every `unsafe` block carries a specific safety justification" + rule is machine-checked. The blocks it flagged were the hardening tests that + fabricate malformed `RM_FILTER_INFO` records, which is exactly where the + invariants most needed writing down. The release workflow requires a dated `## [0.1.0] - YYYY-MM-DD` heading on the commit that receives the annotated `v0.1.0` tag. The `Unreleased` heading is diff --git a/Cargo.toml b/Cargo.toml index 532c02e..ee4a9fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,8 @@ include = [ "/CONTRIBUTING.md", "/LICENSE-APACHE", "/LICENSE-MIT", + "/LICENSES/**", + "/REUSE.toml", "/Cargo.toml", "/Cargo.lock", ] @@ -38,6 +40,15 @@ tokio = ["dep:tokio"] members = ["xtask"] resolver = "3" +# CONTRIBUTING requires a specific safety justification on every `unsafe` block, +# and ADR 0003 confines unsafe to `src/sys.rs`. This restriction lint makes that +# rule machine-checked instead of a convention. +[workspace.lints.clippy] +undocumented_unsafe_blocks = "deny" + +[lints] +workspace = true + [dependencies] bitflags = "2" thiserror = "2" diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt new file mode 100644 index 0000000..563545d --- /dev/null +++ b/LICENSES/Apache-2.0.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. 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. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor 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, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You 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 the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You 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 such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its 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. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 Yasunobu Sakashita + + 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. diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/LICENSES/CC0-1.0.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 0000000..ed78f1e --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Yasunobu Sakashita + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/REUSE.toml b/REUSE.toml new file mode 100644 index 0000000..9a9f464 --- /dev/null +++ b/REUSE.toml @@ -0,0 +1,49 @@ +version = 1 + +[[annotations]] +path = [ + ".cargo/**", + ".github/**", + ".gitattributes", + ".gitignore", + "_typos.toml", + "api/**", + "Cargo.toml", + "CHANGELOG.md", + "CONTRIBUTING.md", + "deny.toml", + "docs/**", + "examples/**", + "README.md", + "release-plz.toml", + "SECURITY.md", + "src/**", + "tests/**", + "xtask/**", +] +precedence = "override" +SPDX-FileCopyrightText = "2026 Yasunobu Sakashita" +SPDX-License-Identifier = "MIT OR Apache-2.0" + +# Machine-generated lockfiles carry no copyrightable authorship. CC0 keeps +# their redistribution unambiguous without treating them as hand-authored +# dual-licensed source. +[[annotations]] +path = "Cargo.lock" +precedence = "override" +SPDX-FileCopyrightText = "NONE" +SPDX-License-Identifier = "CC0-1.0" + +# Conventional root copies kept for Cargo ecosystem tooling. The canonical +# texts REUSE reads live in LICENSES/. +[[annotations]] +path = "LICENSE-APACHE" +precedence = "override" +SPDX-FileCopyrightText = "NONE" +SPDX-License-Identifier = "Apache-2.0" + +[[annotations]] +path = "LICENSE-MIT" +precedence = "override" +SPDX-FileCopyrightText = "2026 Yasunobu Sakashita" +SPDX-License-Identifier = "MIT" diff --git a/_typos.toml b/_typos.toml new file mode 100644 index 0000000..222209b --- /dev/null +++ b/_typos.toml @@ -0,0 +1,6 @@ +[files] +ignore-hidden = false +extend-exclude = [ + ".git/", + "target/", +] diff --git a/src/sys.rs b/src/sys.rs index bb77fd1..c21b183 100644 --- a/src/sys.rs +++ b/src/sys.rs @@ -342,8 +342,10 @@ mod windows { if *ended { return Err(SysError::SessionEnded); } - // Holding `ended` serializes this call with explicit end. An upgraded - // `Arc` also prevents `Drop` until cancellation returns. + // SAFETY: `self.raw` is a live session key. Holding the `ended` + // guard serializes this call against an explicit end, and the + // upgraded `Arc` keeps `Drop` from running until it returns, so the + // session cannot be closed underneath the call. check(unsafe { RmCancelCurrentTask(self.raw) }) } @@ -352,6 +354,9 @@ mod windows { if *ended { return Ok(()); } + // SAFETY: `self.raw` is a live session key, and the `ended` guard is + // held for the whole call, so no other caller can end the same + // session concurrently or observe it as ended before this returns. let result = check(unsafe { RmEndSession(self.raw) }); if result.is_ok() { *ended = true; @@ -882,7 +887,12 @@ mod windows { let record_size = mem::size_of::(); let byte_len = record_size + text.len() * mem::size_of::(); let mut buffer = AlignedBuffer::new(byte_len as u32).unwrap(); + // SAFETY: `buffer` holds `byte_len` bytes, which is `record_size` + // plus the encoded text, so offsetting by `record_size` stays inside + // the allocation and leaves room for `text.len()` UTF-16 units. let text_pointer = unsafe { buffer.as_mut_ptr().add(record_size).cast::() }; + // SAFETY: the destination range was just shown to be in bounds, and + // `text` is a separate allocation, so the regions cannot overlap. unsafe { ptr::copy_nonoverlapping(text.as_ptr(), text_pointer, text.len()); } @@ -895,6 +905,9 @@ mod windows { cbNextOffset: 0, Anonymous: target, }; + // SAFETY: the buffer is at least one record long. The write is + // deliberately unaligned because that is how the Restart Manager + // lays these records out, and the parser must cope with it. unsafe { ptr::write_unaligned(buffer.as_mut_ptr().cast::(), record); } @@ -910,6 +923,10 @@ mod windows { let mut invalid = record; invalid.Anonymous.strFilename = (buffer.as_ptr() as usize + byte_len + 2) as *mut u16; + // SAFETY: only the record header is written, and it fits. The + // `strFilename` value it carries points outside the buffer on + // purpose: the point of the test is that the parser rejects it + // rather than dereferencing it. unsafe { ptr::write_unaligned(buffer.as_mut_ptr().cast::(), invalid); } @@ -920,6 +937,8 @@ mod windows { invalid.cbNextOffset = 1; invalid.Anonymous.strFilename = text_pointer; + // SAFETY: as above, a single in-bounds record header write. The + // sub-record `cbNextOffset` is the malformed input under test. unsafe { ptr::write_unaligned(buffer.as_mut_ptr().cast::(), invalid); } @@ -949,6 +968,8 @@ mod windows { cbNextOffset: 0, Anonymous: Default::default(), }; + // SAFETY: the buffer is `record_size + 4` bytes, so one unaligned + // record header fits. `FilterTrigger` is the invalid input here. unsafe { ptr::write_unaligned(buffer.as_mut_ptr().cast::(), record); } @@ -958,8 +979,12 @@ mod windows { )); record.FilterTrigger = RM_FILTER_TRIGGER_FILE; + // SAFETY: `record_size + 1` is within the `record_size + 4` byte + // allocation. The pointer is intentionally misaligned for `u16`; it + // is only stored in the record, never dereferenced here. record.Anonymous.strFilename = unsafe { buffer.as_mut_ptr().add(record_size + 1).cast::() }; + // SAFETY: one in-bounds unaligned record header write, as above. unsafe { ptr::write_unaligned(buffer.as_mut_ptr().cast::(), record); } @@ -968,8 +993,14 @@ mod windows { Err(SysError::MalformedOutput(_)) )); + // SAFETY: `record_size` is within the `record_size + 4` byte + // allocation, so the pointer is in bounds. record.Anonymous.strFilename = unsafe { buffer.as_mut_ptr().add(record_size).cast::() }; + // SAFETY: all three writes stay inside the `record_size + 4` byte + // allocation -- the header, then two UTF-16 units at `record_size` + // and `record_size + 2`. They are deliberately left unterminated so + // the parser must reject the record instead of running off the end. unsafe { ptr::write_unaligned(buffer.as_mut_ptr().cast::(), record); ptr::write_unaligned( @@ -1044,7 +1075,14 @@ mod windows { let panic = std::panic::catch_unwind(AssertUnwindSafe(|| { let mut callback = |_| panic!("callback panic"); run_with_callback(&mut callback, |native| { + // SAFETY: `run_with_callback` only supplies `native` while + // the lease it just installed is live, so the trampoline and + // the state it reads are both valid for these calls. The + // callback panics on purpose; the trampoline catches it. unsafe { native.unwrap()(50) }; + // SAFETY: as above -- the lease is still held here, and the + // second call proves the trampoline stays usable after the + // first panic was caught. unsafe { native.unwrap()(60) }; ERROR_SUCCESS }) @@ -1055,6 +1093,9 @@ mod windows { let mut called = false; let mut callback = |_| called = true; run_with_callback(&mut callback, |native| { + // SAFETY: the lease installed by `run_with_callback` is live for + // the duration of this closure, so the trampoline pointer and + // the callback state it forwards to are both valid. unsafe { native.unwrap()(100) }; ERROR_SUCCESS }) diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 31891d9..a8b94a1 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -4,6 +4,9 @@ version = "0.0.0" edition = "2024" publish = false +[lints] +workspace = true + [dependencies] thiserror = "2" From daccd26398a151dfbc00057412a0f93768118637 Mon Sep 17 00:00:00 2001 From: Yasunobu <42543015+P4suta@users.noreply.github.com> Date: Mon, 3 Aug 2026 20:49:41 +0900 Subject: [PATCH 2/2] ci: install reuse and typos as tools instead of using their actions fsfe/reuse-action and crate-ci/typos are not on this repository's Actions allowlist, so the CI workflow failed at startup rather than running. The allowlist is a deliberate security control, so install both tools directly rather than widening it; taiki-e/install-action is already allowed. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7254075..14531e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,8 +47,16 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - uses: fsfe/reuse-action@676e2d560c9a403aa252096d99fcab3e1132b0f5 # v6.0.0 - - uses: crate-ci/typos@bee27e3a4fd1ea2111cf90ab89cd076c870fce14 # v1.48.0 + # reuse and typos are installed as tools rather than run through + # fsfe/reuse-action and crate-ci/typos, neither of which is on this + # repository's Actions allowlist. Keeping the allowlist unchanged is + # deliberate; taiki-e/install-action is already allowed. + - run: python -m pip install "reuse[charset-normalizer]==6.2.0" + - uses: taiki-e/install-action@41049aa56687c35e0afa74eed4f09cec4f9afabf # v2.85.2 + with: + tool: typos-cli@1.48.0 + - run: python -m reuse lint + - run: typos windows-quality: name: Windows 2022 quality, native, and E2E