Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2eaa83c
chore(casting): adopt the Casting plane
Enginex0 Jun 17, 2026
aabd8b1
chore: remove decorative divider comments
Enginex0 Jun 17, 2026
ec9d8e9
chore: mark internal crates publish=false
Enginex0 Jun 17, 2026
0017352
refactor(propdetect): sort findings by severity key
Enginex0 Jun 17, 2026
cc73385
chore: format the workspace with rustfmt
Enginex0 Jun 17, 2026
727ba7e
chore: pin rust toolchain to 1.96.0
Enginex0 Jun 17, 2026
55f9893
chore(ci): run the full Rust wall on PRs
Enginex0 Jun 17, 2026
16cc2d5
fix(ci): drop cross targets from toolchain pin
Enginex0 Jun 17, 2026
a1fba84
feat: add --check dry-run to init hook install
Enginex0 Jun 18, 2026
652c2a7
test: add per-arch ptrace smoke fixtures
Enginex0 Jun 18, 2026
6004ca2
chore(bucket): mark T07, T14 done
Enginex0 Jun 18, 2026
d5beea8
feat(seal): throttle init-hook install retries
Enginex0 Jun 18, 2026
4dacb99
refactor(seal): consolidate libc-row finder
Enginex0 Jun 18, 2026
77e7637
chore(bucket): mark T08, T18 done
Enginex0 Jun 18, 2026
a98a5b7
feat(seal): map the hook page from a memfd
Enginex0 Jun 18, 2026
54494f6
chore(bucket): mark T09 done
Enginex0 Jun 18, 2026
07740f6
feat(seal): observe-init snoop with hook hardening
Enginex0 Jun 18, 2026
d863ab2
feat(cli): repeatable --seal and --observe-init
Enginex0 Jun 18, 2026
fa6fe71
chore: ignore the serena scratch directory
Enginex0 Jun 18, 2026
3ddd86a
chore(bucket): close T06, T10, T17
Enginex0 Jun 18, 2026
277525d
chore: format the workspace with rustfmt
Enginex0 Jun 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .context/.gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# .context/.gitignore - managed by the Mold stamp
#
# experimental/ is a persistent scratch workspace for decompiled artifacts,
# pulled device files, and in-flight analysis. Contents are intentionally not
# versioned; commit specific subpaths only when they become stable deliverables
# (then move them out of experimental/ into src/, docs/, etc.).
# experimental/ is a persistent scratch workspace for decompiled
# artifacts, pulled device files, and in-flight analysis. Contents
# are intentionally not versioned; commit specific subpaths only when
# they become stable project deliverables (then move them out of
# experimental/ into the correct location: src/, docs/, etc.).

experimental/*
!experimental/.gitkeep
Expand Down
Empty file added .context/experimental/.gitkeep
Empty file.
32 changes: 32 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.{kt,kts}]
# Line-length ceiling 300: the standard across these projects. A generous
# ceiling so the gate fires only on genuinely unreadable lines. Note ktlint
# cannot auto-fix an over-long line (it will not break it for you), so a line
# past 300 must be wrapped by hand — rare at this ceiling.
max_line_length = 300
# Non-auto-fixable comment-placement rules: ktlint flags these but will not fix
# them, so they cannot belong to a deterministic auto-format gate. Both guard
# legitimate, readable patterns (labelled Java-interop bool args; an explanatory
# comment on a single-line if-guard). Comment placement is a sign-plane (review)
# concern, not a bump-plane (auto-fix) one.
ktlint_standard_comment-wrapping = disabled
ktlint_standard_if-else-wrapping = disabled

[*.{c,cc,cpp,h,hpp}]
indent_size = 2

[*.{yml,yaml,toml,json}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false
9 changes: 9 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh
# Mold casting hook: the fast structural gate (gatesFast) on commit.
# A convenience pre-check, never the wall: `--no-verify` walks past this, the
# release build does not (ADR-0002). gatesFast also runs on every variant build.
set -e
if [ -x ./gradlew ]; then
exec ./gradlew gatesFast --quiet
fi
echo "mold pre-commit: no ./gradlew found; skipping gatesFast" >&2
10 changes: 10 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
# Mold casting hook: the full wall (gatesFull) on push.
# A convenience pre-check, never the wall: `--no-verify` walks past this, the
# release build does not (ADR-0002). gatesFull also binds at assembleRelease /
# bundleRelease. Inert where there is no push target (local-only developer).
set -e
if [ -x ./gradlew ]; then
exec ./gradlew gatesFull --quiet
fi
echo "mold pre-push: no ./gradlew found; skipping gatesFull" >&2
47 changes: 30 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,32 @@ jobs:
- name: Tests
run: cargo test -p resetprop

gates:
name: Casting wall (fmt, clippy, supply, comment-hygiene)
runs-on: ubuntu-latest
steps:
Comment on lines +26 to +29

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Suggested change
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

- uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/ci.yml | head -50

Repository: 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:


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.

Suggested change
- 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


- name: Resolve pinned toolchain (rust-toolchain.toml)
run: rustup show

- name: Format
run: cargo fmt --all --check

- name: Clippy (workspace, all targets and features)
run: cargo clippy --all-targets --all-features -- -D warnings

- name: Install cargo-deny
uses: taiki-e/install-action@v2
with:
tool: cargo-deny

- name: Supply line (offline, deterministic)
run: cargo deny check licenses bans sources

- name: Comment hygiene
run: python3 scripts/comment-hygiene.py

cross-compile:
runs-on: ubuntu-latest
strategy:
Expand All @@ -32,10 +58,10 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Pinned toolchain + Android target
run: |
rustup show
rustup target add ${{ matrix.target }}

- name: Install NDK
uses: nttld/setup-ndk@v1
Expand All @@ -51,16 +77,3 @@ jobs:

- name: Build ${{ matrix.target }}
run: cargo build --release --target ${{ matrix.target }}

clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy

- name: Clippy (library)
run: cargo clippy -p resetprop -- -D warnings
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Pinned toolchain + Android target
run: |
rustup show
rustup target add ${{ matrix.target }}

- name: Install NDK
uses: nttld/setup-ndk@v1
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

# seal: regenerable output + agent scratch (keep execution sessions lean)
*.bak
.serena/
graphify-out/
target/
.gradle/
Expand Down
1 change: 1 addition & 0 deletions .mold/structure-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.1.13
18 changes: 9 additions & 9 deletions bucket/resetprop-rs-injectrc-ports/progress.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
plan: resetprop-rs-injectrc-ports
updated: 2026-06-17
updated: 2026-06-18
tasks:
T01: done
T02: done
T03: done
T04: done
T05: done
T06: backlog
T07: backlog
T08: backlog
T09: backlog
T10: backlog
T06: done
T07: done
T08: done
T09: done
T10: done
T11: cut
T12: done
T13: done
T14: backlog
T14: done
T15: done
T16: done
T17: backlog
T18: backlog
T17: done
T18: done
T19: done
14 changes: 14 additions & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Generated by tools/cast.py. VERSION-PIN LOCATION #2 of 2: the convention jar so
// the project's convention plugins can apply mold.kotlin-quality and mold.gates by
// id. Keep in lockstep with the root build's pin (both == castingVersion).
plugins {
`kotlin-dsl`
}

dependencies {
// The mold casting law. The AGP/Kotlin gradlePlugin deps below let Gradle
// generate the type-safe plugin accessors the convention plugins use.
implementation("mold.casting:convention:0.1.13")
// implementation(libs.android.gradlePlugin)
// implementation(libs.kotlin.gradlePlugin)
}
19 changes: 19 additions & 0 deletions build-logic/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Generated by tools/cast.py. build-logic is a standalone included build, so it
// does NOT inherit the root's repositories or version catalog: the law repo is wired
// here SECOND (miss it -> "Could not find mold.casting:convention"), and the same
// 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

gradlePluginPortal()
google()
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

rootProject.name = "build-logic"
84 changes: 84 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Generated by tools/cast.py (the Casting plane).
plugins {
id("mold.rust-gates") version "0.1.13"
id("mold.comment-hygiene") version "0.1.13"
}

// The module-edge dependency guard has NO published plugin (the one gate that is
// project-authored): cast.py emits the task + matrix parser here. Fill in
// gradle/dependency-guard.config with your tier matrix; an illegal edge then fails
// `check` (-> build), not just a review. See casting-adoption.md.
tasks.register("dependencyGuard") {
group = "verification"
description = "Fails any project->project edge outside gradle/dependency-guard.config."
val matrixFile = file("gradle/dependency-guard.config")
val modules = subprojects
doLast {
val matrix = DependencyMatrix.parse(matrixFile.readText())
val violations = modules.flatMap { module ->
module.configurations
.flatMap { it.dependencies }
.filterIsInstance<ProjectDependency>()
.map { it.path }
.distinct()
.filter { it != module.path }
.filterNot { matrix.permits(module.path, it) }
.map { "${module.path} -> $it" }
}.distinct().sorted()
if (violations.isNotEmpty()) {
throw GradleException(
"Dependency guard: ${violations.size} edge(s) outside the matrix:\n" +
violations.joinToString("\n") { " $it" },
)
}
logger.lifecycle("Dependency guard: ${modules.size} modules, every edge within the matrix.")
}
}

subprojects {
tasks.matching { it.name == "check" }.configureEach {
dependsOn(rootProject.tasks.named("dependencyGuard"))
}
}

// A contract target matches face-precise (contract:state); any other by bare tier.
class DependencyMatrix(private val allowed: Map<String, Set<String>>) {
fun permits(source: String, target: String): Boolean {
val targetSegments = target.split(":").filter { it.isNotEmpty() }
val spec = if (targetSegments.firstOrNull() == "contract" && targetSegments.size >= 2) {
"contract:${targetSegments[1]}"
} else {
targetSegments.firstOrNull().orEmpty()
}
return spec in (allowed[tierOf(source)] ?: emptySet())
}

private fun tierOf(path: String): String =
path.split(":").firstOrNull { it.isNotEmpty() }.orEmpty()

companion object {
fun parse(text: String): DependencyMatrix {
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()
val specs = line.substringAfter("->").trim()
.split(Regex("\\s+")).filter { it.isNotEmpty() }.toSet()
tier to specs
}
return DependencyMatrix(allowed)
}
}
}

// Cross-wire the cargo-root rust gates into each module's wall: the cargo root is a
// plain project, so rust-gates' in-plugin fold finds no local gatesFast/Full; this
// binding makes a broken crate fail the same wall (enforcement.md, ADR-0010).
subprojects {
tasks.matching { it.name == "gatesFast" }
.configureEach { dependsOn(rootProject.tasks.named("rustGatesFast")) }
tasks.matching { it.name == "gatesFull" }
.configureEach { dependsOn(rootProject.tasks.named("rustGatesFull")) }
}
35 changes: 35 additions & 0 deletions config/detekt/detekt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Casting-plane detekt config — the WHOLE active rule set, not an override.
# The mold.kotlin-quality convention plugin sets buildUponDefaultConfig = false,
# so detekt's 200-rule default set is OFF and only the rules turned on below run.
#
# enforcement.md scopes this gate to two things and nothing else:
# - swallowed / empty / over-generic exceptions (bump)
# - a LargeClass / LongMethod hard ceiling (bump at the ceiling only)
# The soft size budget is a sign-plane (judgment) concern, not a deterministic
# gate, so detekt enforces only the hard ceiling here. Formatting belongs to
# Spotless/ktlint, never detekt — no formatting or style rules live in this file.
#
# Per ADR-0007 (certainty over severity): gate only what we are certain about.
# Widening this set is an ADR plus a canary promotion, not an edit.

# EmptyCatchBlock is in detekt's empty-blocks ruleset, not exceptions.
empty-blocks:
active: true
EmptyCatchBlock:
active: true

exceptions:
active: true
SwallowedException:
active: true
TooGenericExceptionCaught:
active: true

complexity:
active: true
LargeClass:
active: true
threshold: 600
LongMethod:
active: true
threshold: 60
13 changes: 13 additions & 0 deletions config/license/allowed-licenses.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"_comment": "Casting-plane JVM license allowlist read by the first-party checkLicense gate in mold.jvm-supply: an external dependency whose POM license matches none of these regexes fails gatesFull. Mirrors the deny.toml policy for the Rust half. A dependency whose license the gate cannot read directly (e.g. declared only in a parent POM) is frozen with a per-module entry ({ \"moduleName\": \"group:artifact\" }) — the brownfield mechanism. Widening the license SET (not a per-module freeze) is an ADR plus a canary promotion.",
"allowedLicenses": [
{ "moduleLicense": ".*Apache.*" },
{ "moduleLicense": ".*MIT.*" },
{ "moduleLicense": ".*BSD.*" },
{ "moduleLicense": ".*ISC.*" },
{ "moduleLicense": ".*Unicode.*" },
{ "moduleLicense": ".*CC0.*" },
{ "moduleLicense": ".*Zlib.*" },
{ "moduleLicense": ".*Public Domain.*" }
]
}
1 change: 1 addition & 0 deletions crates/propdetect-bionic/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[package]
publish = false # internal workspace crate, not a crates.io artifact
name = "propdetect-bionic"
version = "0.1.0"
edition = "2021"
Expand Down
Loading
Loading