Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6a2361a
test: property suite for unit-quantity algebra (StreamData)
markovejnovic Jun 23, 2026
f93f789
test: property suite for Controls.Rate branch and formula invariants
markovejnovic Jun 23, 2026
f1d89b4
test: bound Rate regression-property counter at 1 to avoid empty Stre…
markovejnovic Jun 23, 2026
713f983
test: property suite for Controls.Ewma boundedness and unit preservation
markovejnovic Jun 23, 2026
ad6c4a8
test: generative property suite for /proc/stat parser and CpuTimes
markovejnovic Jun 23, 2026
dbd2b6a
test: generative property suites for NetDev/Diskstats/Meminfo parsers
markovejnovic Jun 23, 2026
10302b1
refactor(suidhelper): split into lib + thin bin to enable integration…
markovejnovic Jun 23, 2026
beecaaa
fix(suidhelper): StrictComponents must reject '.' and empty path comp…
markovejnovic Jun 23, 2026
73ec20f
test: proptest suite for SafePath lexical confinement and relative_to
markovejnovic Jun 23, 2026
04bed70
test: broaden proc-parser property coverage (non-vacuous zero-tail, d…
markovejnovic Jun 23, 2026
18a6657
refactor(suidhelper): collapse StrictComponents check to one raw-segm…
markovejnovic Jun 24, 2026
3b04a08
test(suidhelper): mirror src/ tree -- move safe_path test to tests/util/
markovejnovic Jun 24, 2026
e26d534
test: proptest suite for safe_dev device/name validators
markovejnovic Jun 24, 2026
27a6984
test: property suite for Sys.Linux.Fstab parser
markovejnovic Jun 24, 2026
487e386
test: property suite for Cgroup.V2.Config rendering
markovejnovic Jun 24, 2026
6f644b2
refactor(subid): expose parse/1 as a pure public function
markovejnovic Jun 24, 2026
29effec
test: property suite for Sys.Linux.Subid.parse
markovejnovic Jun 24, 2026
b427fdd
refactor(dmsetup): extract pure dm-table builder functions
markovejnovic Jun 24, 2026
bd52d42
test: property suite for Dmsetup table builders and parse_targets
markovejnovic Jun 24, 2026
85dc8a6
test: polish review findings (broaden safe_dev gen, drop dead fstab a…
markovejnovic Jun 24, 2026
2025cf0
test: widen blockdev_rejects_non_hyper_dm charset so its prop_assume …
markovejnovic Jun 24, 2026
38a2670
test: satisfy credo --strict (map_join, drop quoted property name, sc…
markovejnovic Jun 24, 2026
8abf24a
ci: bump actions/cache v4->v6 and codecov-action v5->v7
markovejnovic Jun 24, 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
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
otp-version: "28"

- name: Cache deps and _build
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: |
deps
Expand All @@ -55,7 +55,7 @@ jobs:
${{ runner.os }}-mix-${{ steps.beam.outputs.otp-version }}-${{ steps.beam.outputs.elixir-version }}-

- name: Cache dialyzer PLTs
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: priv/plts
key: ${{ runner.os }}-plt-${{ steps.beam.outputs.otp-version }}-${{ steps.beam.outputs.elixir-version }}-${{ hashFiles('mix.lock') }}
Expand Down Expand Up @@ -97,7 +97,7 @@ jobs:
run: mix coveralls.json --no-start --warnings-as-errors

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v7
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: cover/excoveralls.json
Expand Down Expand Up @@ -140,7 +140,7 @@ jobs:
run: cargo llvm-cov --all-features --lcov --output-path lcov.info

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v7
with:
token: ${{ secrets.CODECOV_TOKEN }}
# working-directory only applies to `run:` steps, not actions.
Expand Down
27 changes: 22 additions & 5 deletions lib/hyper/suid_helper/dmsetup.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ defmodule Hyper.SuidHelper.Dmsetup do
{:ok, Path.t()} | {:error, err()}
@decorate with_span("Hyper.SuidHelper.Dmsetup.create_snapshot", include: [:name])
def create_snapshot(name, origin_dev, cow_dev, sectors) do
table =
"0 #{sectors} snapshot #{origin_dev} #{cow_dev} P #{Hyper.Node.Config.Img.chunk_sectors()}"

table = snapshot_table(origin_dev, cow_dev, sectors, Hyper.Node.Config.Img.chunk_sectors())
create(name, table, ["--readonly"])
end

Expand All @@ -40,7 +38,7 @@ defmodule Hyper.SuidHelper.Dmsetup do
) :: {:ok, Path.t()} | {:error, err()}
@decorate with_span("Hyper.SuidHelper.Dmsetup.create_thin_pool", include: [:name])
def create_thin_pool(name, meta_dev, data_dev, sectors, block_sectors, low_water) do
table = "0 #{sectors} thin-pool #{meta_dev} #{data_dev} #{block_sectors} #{low_water}"
table = thin_pool_table(meta_dev, data_dev, sectors, block_sectors, low_water)
create(name, table, [])
end

Expand All @@ -53,7 +51,7 @@ defmodule Hyper.SuidHelper.Dmsetup do
{:ok, Path.t()} | {:error, err()}
@decorate with_span("Hyper.SuidHelper.Dmsetup.create_thin_external", include: [:name])
def create_thin_external(name, pool_dev, dev_id, sectors, origin_dev) do
table = "0 #{sectors} thin #{pool_dev} #{dev_id} #{origin_dev}"
table = thin_external_table(pool_dev, dev_id, sectors, origin_dev)
create(name, table, [])
end

Expand Down Expand Up @@ -122,6 +120,25 @@ defmodule Hyper.SuidHelper.Dmsetup do
|> MapSet.new()
end

@doc false
@spec snapshot_table(Path.t(), Path.t(), pos_integer(), pos_integer()) :: String.t()
def snapshot_table(origin_dev, cow_dev, sectors, chunk_sectors) do
"0 #{sectors} snapshot #{origin_dev} #{cow_dev} P #{chunk_sectors}"
end

@doc false
@spec thin_pool_table(Path.t(), Path.t(), pos_integer(), pos_integer(), non_neg_integer()) ::
String.t()
def thin_pool_table(meta_dev, data_dev, sectors, block_sectors, low_water) do
"0 #{sectors} thin-pool #{meta_dev} #{data_dev} #{block_sectors} #{low_water}"
end

@doc false
@spec thin_external_table(Path.t(), non_neg_integer(), pos_integer(), Path.t()) :: String.t()
def thin_external_table(pool_dev, dev_id, sectors, origin_dev) do
"0 #{sectors} thin #{pool_dev} #{dev_id} #{origin_dev}"
end

# Create a dm device named `name` from a reconstructed `table`, with any extra
# create flags (e.g. `--readonly`). Returns the `/dev/mapper/<name>` path.
@spec create(String.t(), String.t(), [String.t()]) :: {:ok, Path.t()} | {:error, err()}
Expand Down
12 changes: 9 additions & 3 deletions lib/sys/linux/subid.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,22 @@ defmodule Sys.Linux.Subid do
content
|> String.split("\n", trim: true)
|> Enum.reduce_while({:ok, []}, fn line, {:ok, acc} ->
case parse_subid_line(line) do
case parse(line) do
{:ok, spec} -> {:cont, {:ok, [spec | acc]}}
{:error, _} = error -> {:halt, error}
end
end)
end
end

@spec parse_subid_line(String.t()) :: {:ok, Spec.t()} | {:error, :invalid_format}
defp parse_subid_line(line) do
@doc """
Parse one `/etc/subuid`/`/etc/subgid` line (`name:start:count`) into a `Spec`,
where `min_id` is `start` and `max_id` is `start + count`. A line that is not
exactly three colon-separated fields, or whose start/count are not integers,
yields `{:error, :invalid_format}`.
"""
@spec parse(String.t()) :: {:ok, Spec.t()} | {:error, :invalid_format}
def parse(line) do
with [name, start_str, count_str] <- String.split(line, ":"),
{start, ""} <- Integer.parse(start_str),
{count, ""} <- Integer.parse(count_str) do
Expand Down
1 change: 1 addition & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ defmodule Hyper.MixProject do
defp deps do
[
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:stream_data, "~> 1.0", only: [:dev, :test], runtime: false},
{:excoveralls, "~> 0.18", only: :test, runtime: false},
{:dialyxir, "~> 1.4", only: [:dev], runtime: false},
{:ex_doc, "~> 0.34", only: :dev, runtime: false},
Expand Down
1 change: 1 addition & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"postgrex": {:hex, :postgrex, "0.22.2", "4aec14df2a72722aee92492566edbeeb44e233ecb86b1915d03136297ef1385d", [:mix], [{:db_connection, "~> 2.9", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8946382ddb06294f56026ac4278b3cc212bac8a2c82ed68b4087819ed1abc53b"},
"req": {:hex, :req, "0.6.2", "b9b2024f35bcf60a92cc8cad2eaaf9d4e7aace463ff74be1afe5986830184413", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.21", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "cc9cd30a2ddd04989929b887178e1610c940456d962c6c3a52df6146d2eef9bf"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"stream_data": {:hex, :stream_data, "1.3.0", "bde37905530aff386dea1ddd86ecbf00e6642dc074ceffc10b7d4e41dfd6aac9", [:mix], [], "hexpm", "3cc552e286e817dca43c98044c706eec9318083a1480c52ae2688b08e2936e3c"},
"telemetry": {:hex, :telemetry, "1.4.2", "a0cb522801dffb1c49fe6e30561badffc7b6d0e180db1300df759faa22062855", [:rebar3], [], "hexpm", "928f6495066506077862c0d1646609eed891a4326bee3126ba54b60af61febb1"},
"telemetry_poller": {:hex, :telemetry_poller, "1.3.0", "d5c46420126b5ac2d72bc6580fb4f537d35e851cc0f8dbd571acf6d6e10f5ec7", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "51f18bed7128544a50f75897db9974436ea9bfba560420b646af27a9a9b35211"},
"tls_certificate_check": {:hex, :tls_certificate_check, "1.33.0", "01e0822a2ebb0b207c4964e8d32ad8b1b8ce1caf58f446e53f816d06db953de4", [:rebar3], [{:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "cab9a7439e2dbfe91b38104f2d8a4b6d61dbc4d3a5ad59ac364713a88c6cfd9b"},
Expand Down
Loading