Casting plane adoption + injectrc seal wave (T07, T14)#1
Conversation
Generated by tools/cast.py: root settings + build-logic (law repo, convention dep), root build (rust-gates + comment-hygiene + the hand-authored dependencyGuard), gradle/libs.versions.toml, deny.toml, detekt + license config, .editorconfig, .githooks, .mold version. core.hooksPath is set to .githooks (pre-commit gatesFast, pre-push gatesFull); both skip cleanly until a gradle wrapper exists.
Box-drawing and dash rules the comment-hygiene gate flags as decorative banners; they carry no information the code does not.
Workspace path-dep consumers, not crates.io artifacts. cargo-deny's wildcard-path ban applies to public crates; this exempts them.
Satisfies clippy unnecessary_sort_by under -D warnings. Severity is Copy + Ord, so Reverse keeps the existing descending order.
Adopt the cargoFmtCheck gate. The tree diverged from rustfmt 1.96.0 defaults; this is the formatting-only pass, kept separate from the substantive changes above.
Pins rustfmt and clippy so CI and local format identically; a newer rustfmt can no longer reformat the tree out from under the gate. Mirrors the Casting law's rust = 1.96.0 and lists the four Android targets so the cross-builds resolve under the pin.
Replaces the library-only clippy check with the Casting wall: cargo fmt --check, clippy --all-targets --all-features -D warnings, cargo deny (offline supply line), and a comment-hygiene scan mirroring the law's banner rule. Host check, tests, and cross-compile are unchanged. CI gates natively (no JVM); the gradle wall stays the local definition.
Listing the Android targets in rust-toolchain.toml made every host cargo command (clippy, fmt) try to download their std libs first, which times out offline or on a slow link, and it broke the clippy gate. Drop them from the pin; the cross-compile sites add the target against the pinned toolchain instead (rustup target add), where the network is both available and actually needed.
Add check_init_hook: resolve stage-A facts (maps + libc ELF + symbol) and the scratch slot under one RemoteAttach window, then detach without poking init. The path runs only the no-side-effect sub-ops of install_init_hook -- no remote_syscall_via_poke, ptrace_poketext, or write_remote -- so init's text and registers are left untouched and no trampoline is installed. Results surface as CheckReport. Wire a --check bool flag into the hand-rolled CLI parser. With --seal it dry-runs the Tier B install and reports the resolved facts instead of writing, letting an operator validate a device before the real poke.
|
Warning Review limit reached
More reviews will be available in 53 minutes and 10 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (16)
📝 WalkthroughWalkthroughThis PR establishes a Gradle build-logic scaffold with version catalog, dependency-guard task, and quality-gate tooling (cargo-deny, detekt, comment-hygiene script, git hooks). CI and release workflows are updated to use ChangesBuild/CI/Quality-gate infrastructure
Rust code reformatting
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
build.gradle.kts (1)
64-70: ⚡ Quick winReject duplicate source-tier rules during matrix parsing.
Using
associatehere silently keeps only the last duplicate tier. That can hide policy mistakes and make guard behavior non-obvious.Suggested fix
- val allowed = text.lineSequence() + val seen = mutableSetOf<String>() + val allowed = text.lineSequence() .map { it.substringBefore('#').trim() } .filter { it.isNotEmpty() } .associate { line -> require("->" in line) { "dependency-guard.config: rule has no '->': `$line`" } val tier = line.substringBefore("->").trim() + require(seen.add(tier)) { + "dependency-guard.config: duplicate source tier: `$tier`" + } val specs = line.substringAfter("->").trim() .split(Regex("\\s+")).filter { it.isNotEmpty() }.toSet() tier to specs }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@build.gradle.kts` around lines 64 - 70, The associate function at line 64 silently keeps only the last duplicate tier when multiple rules have the same source-tier, which can hide policy mistakes. Replace the associate call with logic that builds the map while explicitly validating there are no duplicate tiers - either by using toMap with a custom merging function that throws an error on duplicates, or by collecting the tier-to-specs pairs into a map and adding validation logic that checks for and rejects any duplicate tier keys before returning the result. Ensure the error message clearly indicates which tier rule is duplicated to aid policy debugging.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/ci.yml:
- Around line 26-29: The `gates` job in the GitHub Actions workflow is missing
explicit least-privilege permission declarations, which means it inherits
potentially overpermissive default token permissions. Add a `permissions`
section directly under the `gates` job definition (after the `runs-on` key) to
explicitly declare read-only scopes. Set `contents: read` as the minimum
required permission to allow the job to access repository contents without write
capabilities, ensuring the job operates with least-privilege access control.
- Line 30: The actions/checkout action on line 30 uses a mutable version tag
(`@v4`) instead of a pinned commit SHA, creating supply chain risk. Replace the
`@v4` version tag with the full-length commit SHA for that specific version of the
action. Additionally, add `persist-credentials: false` as a parameter to the
checkout action to prevent the GITHUB_TOKEN from being stored in Git
configuration. Apply the same fixes to the checkout action on line 42 which
currently uses `@v2`.
In `@build-logic/settings.gradle.kts`:
- Line 7: The maven repository URL on line 7 of settings.gradle.kts is
hard-coded to a machine-local mount path
`/mnt/companion/president/maven-casting`, making builds fail in environments
where this mount doesn't exist. Replace the hard-coded path with a Gradle
property or environment variable (e.g., using System.getenv() or Gradle
properties). Apply the same parameterization to line 6 to ensure both casting
and any other machine-specific paths are sourced from configuration rather than
hard-coded, making the build portable across CI and development environments.
In `@crates/resetprop-cli/src/main.rs`:
- Around line 265-284: The check flag validation is only enforced within the
seal branch (inside the if check block at line 265), which allows --check
without --seal to be silently ignored and execute normal mutation paths instead.
Move the check flag validation logic to an earlier point in the function
execution flow, before the normal mutation path begins, to enforce the contract
that --check should either require a specific context like --seal or should
reject conflicting positional arguments. Add validation that raises an error
when --check is passed without appropriate context or with mutation-related
arguments that would conflict with the dry-run expectation.
In `@scripts/comment-hygiene.py`:
- Line 56: The Path.read_text() call on line 56 can throw an OSError when a
tracked file is unreadable, which terminates the script with a traceback. Wrap
the file reading operation in a try-except block that catches OSError, and
instead of letting the exception propagate, implement a controlled failure path
such as skipping that file or logging a warning and continuing with the next
file. This ensures the script handles unreadable files gracefully without
crashing.
---
Nitpick comments:
In `@build.gradle.kts`:
- Around line 64-70: The associate function at line 64 silently keeps only the
last duplicate tier when multiple rules have the same source-tier, which can
hide policy mistakes. Replace the associate call with logic that builds the map
while explicitly validating there are no duplicate tiers - either by using toMap
with a custom merging function that throws an error on duplicates, or by
collecting the tier-to-specs pairs into a map and adding validation logic that
checks for and rejects any duplicate tier keys before returning the result.
Ensure the error message clearly indicates which tier rule is duplicated to aid
policy debugging.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 36636745-2b3b-44d6-b514-2339b703c1be
📒 Files selected for processing (55)
.context/.gitignore.context/experimental/.gitkeep.editorconfig.githooks/pre-commit.githooks/pre-push.github/workflows/ci.yml.github/workflows/release.yml.mold/structure-versionbucket/resetprop-rs-injectrc-ports/progress.ymlbuild-logic/build.gradle.ktsbuild-logic/settings.gradle.ktsbuild.gradle.ktsconfig/detekt/detekt.ymlconfig/license/allowed-licenses.jsoncrates/propdetect-bionic/Cargo.tomlcrates/propdetect-bionic/src/main.rscrates/propdetect/Cargo.tomlcrates/propdetect/src/heuristics.rscrates/propdetect/src/main.rscrates/propdetect/src/snapshot.rscrates/propdetect/tests/detect_manipulation.rscrates/resetprop-cli/Cargo.tomlcrates/resetprop-cli/src/main.rscrates/resetprop/src/area.rscrates/resetprop/src/bionic.rscrates/resetprop/src/compact.rscrates/resetprop/src/context.rscrates/resetprop/src/dict.rscrates/resetprop/src/error.rscrates/resetprop/src/harvest.rscrates/resetprop/src/info.rscrates/resetprop/src/inspect.rscrates/resetprop/src/lib.rscrates/resetprop/src/mock.rscrates/resetprop/src/persist/io.rscrates/resetprop/src/persist/mod.rscrates/resetprop/src/persist/proto.rscrates/resetprop/src/seal/arena.rscrates/resetprop/src/seal/elf.rscrates/resetprop/src/seal/hook.rscrates/resetprop/src/seal/maps.rscrates/resetprop/src/seal/ptrace.rscrates/resetprop/src/trie.rscrates/resetprop/tests/elf_fixture_smoke.rscrates/resetprop/tests/ptrace_core_smoke.rscrates/resetprop/tests/ptrace_core_smoke_arm.rscrates/resetprop/tests/ptrace_core_smoke_x86.rscrates/resetprop/tests/ptrace_core_smoke_x86_64.rscrates/resetprop/tests/tier_a_child_smoke.rsdeny.tomlgradle/dependency-guard.configgradle/libs.versions.tomlrust-toolchain.tomlscripts/comment-hygiene.pysettings.gradle.kts
| gates: | ||
| name: Casting wall (fmt, clippy, supply, comment-hygiene) | ||
| runs-on: ubuntu-latest | ||
| steps: |
There was a problem hiding this comment.
Set explicit least-privilege permissions for the new gates job.
The new job currently inherits default token permissions. Declare read-only scope explicitly to avoid accidental write-capable defaults.
Suggested fix
gates:
name: Casting wall (fmt, clippy, supply, comment-hygiene)
runs-on: ubuntu-latest
+ permissions:
+ contents: read
steps:📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| gates: | |
| name: Casting wall (fmt, clippy, supply, comment-hygiene) | |
| runs-on: ubuntu-latest | |
| steps: | |
| gates: | |
| name: Casting wall (fmt, clippy, supply, comment-hygiene) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: |
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 26-50: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block
(excessive-permissions)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/ci.yml around lines 26 - 29, The `gates` job in the GitHub
Actions workflow is missing explicit least-privilege permission declarations,
which means it inherits potentially overpermissive default token permissions.
Add a `permissions` section directly under the `gates` job definition (after the
`runs-on` key) to explicitly declare read-only scopes. Set `contents: read` as
the minimum required permission to allow the job to access repository contents
without write capabilities, ensuring the job operates with least-privilege
access control.
Source: Linters/SAST tools
| name: Casting wall (fmt, clippy, supply, comment-hygiene) | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/ci.yml | head -50Repository: Enginex0/resetprop-rs
Length of output: 1528
🌐 Web query:
GitHub Actions security best practices pin commit SHA persist-credentials
💡 Result:
Securing GitHub Actions workflows involves two critical best practices: pinning actions to immutable commit SHAs and properly managing credential persistence. Pinning Actions to Commit SHAs Using version tags (e.g., @v4) or branch names (e.g., @main) for GitHub Actions introduces significant supply chain risk because these references are mutable [1][2]. An attacker who compromises an action's repository can force-push malicious code to an existing tag or branch, causing all workflows that reference that tag to automatically execute the malicious code [1][3][4]. Pinning to a full-length commit SHA is the only way to treat an action as an immutable release [5][3]. Because a commit SHA cryptographically identifies a specific Git object, it cannot be redirected to different code [1][6]. - Implementation: Replace tag references with the full-length commit SHA [5][4]. To maintain readability, include the original version tag as a comment [7][4]. - Example: - uses: actions/checkout@11bd719 # v4.2.2 - Automation: Use tools like Renovate with presets (e.g., helpers:pinGitHubActionDigests) to automatically create pull requests that update SHA pins whenever the referenced tag moves, ensuring security without significant maintenance overhead [1][2][7]. - Enforcement: Organizations can enable policies to mandate commit SHA pinning across all repositories, causing any workflow using mutable tags to fail [5][6][7]. Managing Credential Persistence The actions/checkout action, by default, persists Git credentials (including the GITHUB_TOKEN) into the runner's local Git configuration [8][9][10]. If a workflow is compromised, a malicious step or third-party action can access these credentials to perform unauthorized operations, such as pushing commits or accessing other repository secrets [11][8][10]. - Implementation: Always set persist-credentials to false unless your workflow explicitly requires Git authentication to push changes back to the repository [8][10][12]. - Example: - uses: actions/checkout@11bd719 with: persist-credentials: false - Context: While newer versions of actions/checkout (v6+) store persisted credentials in a temporary runner path ($RUNNER_TEMP) rather than directly in.git/config, setting persist-credentials to false remains a critical best practice to prevent credential exposure [13][9]. - Alternative: If you need to push changes, prefer using the GITHUB_TOKEN with defined, minimum-required permissions rather than relying on persisted credentials [1][10][12].
Citations:
- 1: https://www.systemshardening.com/articles/cicd/github-actions-trivy-compromise/
- 2: https://emmer.dev/blog/pin-your-github-actions-to-protect-against-mutability/
- 3: https://nearform.com/insights/why-you-should-pin-your-github-actions-by-commit-hash/
- 4: https://docs.bswen.com/blog/2026-03-26-github-actions-supply-chain-security/
- 5: https://docs.github.com/en/actions/reference/security/secure-use
- 6: https://www.romainlespinasse.dev/posts/github-actions-commit-sha-pinning/
- 7: https://architecture.lullabot.com/adr/20260505-pin-github-actions-to-hash/
- 8: https://adaptive-enforcement-lab.com/secure/github-actions-security/third-party-actions/common-actions/
- 9: https://sisaku-security.github.io/lint/docs/rules/artipacked/
- 10: https://actsense.dev/vulnerabilities/unsafe_checkout/
- 11: https://cheatsheetseries.owasp.org/cheatsheets/GitHub_Actions_Security_Cheat_Sheet.html
- 12: https://release-plz.dev/docs/github/persist-credentials
- 13: actions/checkout@v5.0.1...v6.0.0
Pin third-party actions to commit SHAs and disable checkout credential persistence.
Lines 30 and 42 use mutable action version tags (@v4 and @v2), which expose the workflow to supply chain risk if those tags are force-pushed with malicious code. Pin both to full-length commit SHAs instead. Additionally, add persist-credentials: false to the checkout action to prevent the GITHUB_TOKEN from being stored in Git configuration, reducing token exposure if a workflow step is compromised.
Suggested fix
- - uses: actions/checkout@v4
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ persist-credentials: false- - name: Install cargo-deny
- uses: taiki-e/install-action@v2
+ - name: Install cargo-deny
+ uses: taiki-e/install-action@<commit-sha> # v2📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - uses: actions/checkout@v4 | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| persist-credentials: false |
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 30-30: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 30-30: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/ci.yml at line 30, The actions/checkout action on line 30
uses a mutable version tag (`@v4`) instead of a pinned commit SHA, creating supply
chain risk. Replace the `@v4` version tag with the full-length commit SHA for that
specific version of the action. Additionally, add `persist-credentials: false`
as a parameter to the checkout action to prevent the GITHUB_TOKEN from being
stored in Git configuration. Apply the same fixes to the checkout action on line
42 which currently uses `@v2`.
Source: Linters/SAST tools
| // gradle/libs.versions.toml is imported by path so the catalog stays one SSOT. | ||
| dependencyResolutionManagement { | ||
| repositories { | ||
| maven { url = uri("file:///mnt/companion/president/maven-casting") } // mold casting law repo |
There was a problem hiding this comment.
Parameterize the Casting Maven repo path instead of hard-coding a machine-local mount.
Line 7 binds plugin resolution to /mnt/companion/president/maven-casting; environments without that mount will fail during settings evaluation. Please source this from a Gradle property/env var (and apply the same fix to settings.gradle.kts Line 6) to keep CI/dev setups portable.
Suggested direction
- maven { url = uri("file:///mnt/companion/president/maven-casting") }
+ val castingRepo = providers.gradleProperty("castingRepoUrl")
+ .orElse(System.getenv("CASTING_REPO_URL") ?: "")
+ .get()
+ require(castingRepo.isNotBlank()) { "Missing casting repo URL. Set -PcastingRepoUrl or CASTING_REPO_URL." }
+ maven { url = uri(castingRepo) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@build-logic/settings.gradle.kts` at line 7, The maven repository URL on line
7 of settings.gradle.kts is hard-coded to a machine-local mount path
`/mnt/companion/president/maven-casting`, making builds fail in environments
where this mount doesn't exist. Replace the hard-coded path with a Gradle
property or environment variable (e.g., using System.getenv() or Gradle
properties). Apply the same parameterization to line 6 to ensure both casting
and any other machine-specific paths are sourced from configuration rather than
hard-coded, making the build portable across CI and development environments.
| if check { | ||
| // Dry-run: resolve the Tier B facts in init without poking it. No | ||
| // value is written and no trampoline is installed, so VALUE is not | ||
| // required here. INIT_PID is `1` (crate-internal in resetprop). | ||
| return match resetprop::seal::hook::check_init_hook(1) { | ||
| Ok(r) => { | ||
| println!( | ||
| "check [{name}]: libc_base={:#x} libc_end={:#x} target_fn={:#x} scratch_pc={:#x}", | ||
| r.libc_base, r.libc_end, r.target_fn, r.scratch_pc | ||
| ); | ||
| Ok(()) | ||
| } | ||
| Err( | ||
| e @ (Error::HookInstallFailed(_) | ||
| | Error::ElfParse(_) | ||
| | Error::SymbolNotFound(_)), | ||
| ) => Err(format!("Tier B dry-run failed: {e}")), | ||
| Err(e) => Err(format!("check failed: {e}")), | ||
| }; | ||
| } |
There was a problem hiding this comment.
Enforce --check contract strictly to avoid unintended writes.
Line 265 currently treats check only inside the --seal branch, so --check without --seal is silently ignored; and in the dry-run branch, extra positional args are ignored. This can mislead operators into expecting a no-write run while executing a normal mutation path.
💡 Suggested fix
@@
if seal_flag_count > 1 {
@@
}
+ if check && seal.is_none() {
+ return Err("--check requires --seal".to_string());
+ }
@@
if let Some(ref name) = seal {
if check {
+ if !positional.is_empty() {
+ return Err("--seal --check does not accept VALUE or positional args".to_string());
+ }
// Dry-run: resolve the Tier B facts in init without poking it. No🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/resetprop-cli/src/main.rs` around lines 265 - 284, The check flag
validation is only enforced within the seal branch (inside the if check block at
line 265), which allows --check without --seal to be silently ignored and
execute normal mutation paths instead. Move the check flag validation logic to
an earlier point in the function execution flow, before the normal mutation path
begins, to enforce the contract that --check should either require a specific
context like --seal or should reject conflicting positional arguments. Add
validation that raises an error when --check is passed without appropriate
context or with mutation-related arguments that would conflict with the dry-run
expectation.
| return 2 | ||
| violations = [] | ||
| for rel in files: | ||
| text = Path(rel).read_text(encoding="utf-8", errors="replace") |
There was a problem hiding this comment.
Handle unreadable tracked files without crashing the gate.
Line 56 can throw OSError and terminate the script with a traceback. Return a controlled failure path instead.
Suggested fix
- text = Path(rel).read_text(encoding="utf-8", errors="replace")
+ try:
+ text = Path(rel).read_text(encoding="utf-8", errors="replace")
+ except OSError as exc:
+ print(f"comment-hygiene: cannot read {rel}: {exc}", file=sys.stderr)
+ return 2🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/comment-hygiene.py` at line 56, The Path.read_text() call on line 56
can throw an OSError when a tracked file is unreadable, which terminates the
script with a traceback. Wrap the file reading operation in a try-except block
that catches OSError, and instead of letting the exception propagate, implement
a controlled failure path such as skipping that file or logging a warning and
continuing with the next file. This ensures the script handles unreadable files
gracefully without crashing.
A failed install retries on every seal() call while the hook slot is empty, so a load that crashes init can bootloop it. Cap hard failures per process: install_init_hook refuses with HookInstallFailed once a module-static AtomicU32 hits MAX_INSTALL_HARD_FAILURES (5, mirroring ReZygisk's MAX_RETRY_COUNT) before the M1 identity check or any ptrace attach. The counter is module-static because the failures it counts never produce a HookHandle.
arena and hook carried divergent libc.text predicates; only hook's was hardened (exact r-xp + path ends_with /libc.so). Promote it to a shared find_libc_text_row driving both the stage-A and Tier A remap finders, deleting arena's looser r-x + libc.so.* match that could pick a shared copy or a versioned sibling. Also bind LOCK_LIST_CAPACITY < PATH_STAGE_OFFSET with a const-assert so a future capacity bump fails the build instead of letting the in-init walker read the staged path bytes, and clear doc-rot: the append capacity rationale (the hook body moved off this page in 563e6a3), the empty-list sentinel wording, arena's remote_syscall_via_poke flow doc, and mod.rs's stale "deferred re-exports" note.
Replace the host-file hook-page dance (write under /data/adb/resetprop-rs, remote openat, mmap, unlink) with injectrc's memfd pattern: the tracee creates an anonymous memfd, this process fills it through /proc/<pid>/fd/<memfd> and relabels it to the libc.so SELinux context via setfilecon, then the tracee maps and closes its own fd. The mapping survives the close via the fd's anonymous inode, so nothing reaches disk: no hook-*.bin residue and no adb_data_file:file execute denial to dodge. The libselinux relabel is hand-rolled FFI (no selinux-sys crate). The NDK ships no libselinux to link against, so the Android path resolves getfilecon/setfilecon/freecon at runtime via dlopen rather than #[link]; the host build compiles a shim that reports the op unsupported. The remote syscall sequence (memfd_create, mmap, close) runs behind a closure seam so it is exercised off-device with mocked syscalls. On-device acceptance (zero hook-*.bin residue, no new avc denial) needs real aarch64 init and is not validated here.
Code + host acceptance complete; on-device residue/avc checks pending hardware (see a98a5b7).
- Add observe-init: a whole-thread-group PTRACE_SYSCALL snoop of init's write(/dev/kmsg) traffic, with per-arch syscall_nr/arg accessors and GET_SYSCALL_INFO entry detection. - Fold the staged-trap injector into one run_remote_payload skeleton shared by the syscall and ISB paths (arena, hook). - Fold first-seal install + trampoline + first append under one thread-group stop; add install_and_seal_first / FirstSeal. - Resolve target_fn against the ELF load bias, not the r-xp segment start, so the trampoline lands on __system_property_update instead of a neighbouring function.
- Make --seal repeatable in one run so a single process builds a multi-entry lock list under one shared hook handle, removing the one-seal-per-boot trap. - Add --observe-init [--duration SECS] to dump init's /dev/kmsg writes via PropSystem::observe_init. - Refresh usage and options text.
- .serena/ holds codeintel cache and project config, not source.
- T06 Tier B on-device gate, T10 kmsg snoop, and T17 injector consolidation now complete.
- rustfmt the observe-init/multi-seal additions and the pre-existing selinux row, so the CI fmt gate passes.
Summary
Brings
feat/casting-planetomain: Casting-plane build/CI adoption plus thefirst parallel wave of the
resetprop-rs-injectrc-portsbucket. Two independentthreads on one branch.
Build / CI / toolchain (8 commits)
settings.gradle.kts,scripts/comment-hygiene.py)publish=false; drop decorative divider commentsrefactor(propdetect): sort findings by severity keyinjectrc seal wave — T07, T14
feat: add --check dry-run to init hook install— a no-poke dry-run throughinstall_init_hook(identity guard, attach, resolve symbol, locate scratch slot) that returns the resolved facts without writing into init, wired to a--checkflag in the hand-rolled CLI parser. The no-write guarantee is statically grounded: the dry-run path and its transitive callees hold zero ptrace-write primitives.test: add per-arch ptrace smoke fixtures— x86_64/arm/x86 sibling test files (#![cfg(target_arch = ...)]) asserting per-arch trap/breakpoint encodings and the NT_PRSTATUS regset layout. The aarch64 fixture is unchanged.Verification (host)
cargo test -p resetprop: green (151 lib + 3 native x86_64 fixtures + 2 doctests)cargo clippy -p resetprop --all-targets -- -D warnings: cleancargo fmt --check: cleanAcceptance edges CI cannot cover
--checkzero-AVC behavior needs a live aarch64 init (device-gated).cargo check --teststype-checks and codegens clean on all three Android triples here.Environmental gates, not regressions.
Summary by CodeRabbit
Release Notes
New Features
--checkflag support with seal mode for dry-run verification of hook initializationInfrastructure