Skip to content

Add support for analysing Setup Factory installers#26

Draft
Tom Plant (pl4nty) wants to merge 50 commits into
mainfrom
claude/setup-factory-analysis-2yb6iz
Draft

Add support for analysing Setup Factory installers#26
Tom Plant (pl4nty) wants to merge 50 commits into
mainfrom
claude/setup-factory-analysis-2yb6iz

Conversation

@pl4nty

@pl4nty Tom Plant (pl4nty) commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary

Adds detection and analysis of Indigo Rose Setup Factory installers, such as DIALux evo.

Setup Factory setup executables are a self-extracting stub wrapping the irsetup.exe run-time, with a compressed archive in the PE overlay. This detector:

  1. Detects the installer from the 16-byte Setup Factory 8/9 overlay signature (with the run-time assembly manifest Setup Factory Run-time and the Created with Setup Factory version-info comment kept as fallbacks for older/repacked stubs).
  2. Parses the archive in the overlay to recover the compiled setup script (irsetup.dat) and reads its session variable table — the real values the author entered in the designer (%ProductName%, %CompanyName%, %ProductVer%).
  3. Emits an exe installer with the documented /S silent switch and an AppsAndFeaturesEntries built from the recovered metadata.

Why parse the binary instead of the PE version info

The setup stub's PE version info describes the run-time, not the packaged app — and authors frequently leave it at the Setup Factory defaults (gloCOM/Communicator would otherwise report DisplayName: Setup Factory Runtime, publisher Indigo Rose Corporation). The real product name/publisher/version live in the compiled script inside the overlay archive, so that's what we read. The archive format, XOR obfuscation and compression handling follow CybercentreCanada/sfextract.

Notes:

  • The script is LZMA- or LZMA2-compressed, decoded via the already-vendored liblzma. Large embedded files are seeked past so only the small script (well under 1 MB) is buffered — no full-payload extraction.
  • %ProductVer% is author-defined and is sometimes a bare major number (gloCOM ships "4"; the real version lives in a custom variable), so it's only used when it looks like a real dotted version.

Changes

  • New src/analysis/installers/setup_factory/ module:
    • mod.rs — detection, best-effort metadata extraction, installer emission.
    • archive.rs — walks the overlay archive and decompresses irsetup.dat.
    • script.rs — parses the session variable table (with unit tests).
  • Registered the module in src/analysis/installers/mod.rs and wired SetupFactory into the Exe detection chain in src/analysis/installers/exe.rs.

Verification

Tested end-to-end with komac analyze against real Setup Factory installers — see the results comment below. cargo build, cargo clippy (-D warnings), and cargo test (session-variable parser) all pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_012BX4kXe76SvBKY3BySbzRN

Tom Plant (pl4nty) and others added 30 commits June 17, 2026 03:27
Signed-off-by: Tom Plant <tom@tplant.com.au>
7zip, SFXCab, InstallShield, Squirrel, UPX, WExtract

Signed-off-by: Tom Plant <tom@tplant.com.au>
Signed-off-by: Tom Plant <tom@tplant.com.au>
Signed-off-by: Tom Plant <tom@tplant.com.au>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
… and vanity URLs

Signed-off-by: Tom Plant <tom.plant@devicie.com>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
Edge cases like version not matching github, or multiple channels

Signed-off-by: Tom Plant <tom.plant@devicie.com>
useful when a package ID changes. could copy versions to the new ID, but that's a lot of validation requests

Signed-off-by: Tom Plant <tom.plant@devicie.com>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
…tegies to file

Signed-off-by: Tom Plant <tom.plant@devicie.com>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
Signed-off-by: Tom Plant <tom.plant@devicie.com>
Workspace is set to use Rust v1.93 even though the module is 1.89

Signed-off-by: Tom Plant <tom.plant@devicie.com>
Tom Plant (pl4nty) and others added 14 commits June 17, 2026 03:28
Inno Setup 6.2 introduced a new PrivilegesRequired setting 'requireadmin'
(value 4), which requires administrative privileges and will refuse to run
if they cannot be obtained, unlike 'admin' which will prompt for credentials.

Previously, reading this value with TryFromBytes failed since the enum only
contained values 0-3. The failure was silently swallowed by unwrap_or_default(),
returning None instead of the actual value.
…flag

In Inno Setup 6.4.x, the decrypt_dll was removed from the wizard section as
encryption is now handled via the inline EncryptionHeader. However, the
ENCRYPTION_USED flag can still be set in the header flags bitfield.

Previously, when ENCRYPTION_USED was set, the parser tried to read decrypt_dll
from the wizard section regardless of version, causing UnexpectedEof for Inno
6.4.x installers that do not store decrypt_dll.

Also revert the error suppression that converted UnexpectedEof to NotInnoFile,
which was masking the root cause.
The non-solid NSIS header detection checked for an exact byte value of 0x80
in the high byte of compressed_header_size (signature.get(3) == Some(&0x80)).
This missed valid non-solid installers where the high byte has other bits set
in addition to the IS_COMPRESSED_MASK bit (e.g. 0x8D for timi.exe).

The correct check is to test the IS_COMPRESSED_MASK bit directly:
  (compressed_header_size & IS_COMPRESSED_MASK) != 0

Additionally, installers with the BI_EXTERNAL_FILE flag set store their data
in an external file and cannot be analysed inline. These are now rejected
early with NotNsisFile instead of failing later in header decompression.

The map_err suppression on Header::decompress is also removed; genuine
decompression errors are now propagated as-is.
The NSIS header's language_table_size field is unreliable for old installers:
it can be 0 (typefaster.exe) or -1 (quickpar.exe) even when valid language
tables are present in the LangTables block.

Fix this by computing the size from the block data, matching the approach
already used for sections:
  lang_table_size = lang_block_data.len() / num_tables

This uses the actual block data size divided by the number of language table
entries reported in the block header, which is always correct.

Also removes the now-unnecessary header parameter from primary_language().
… values

The FileOpen entry (type 55) stores a file creation disposition value
that NSIS passes directly to CreateFile(). NSIS uses values like 0 and
700 that are not valid Win32 OPEN_EXISTING (3) / CREATE_ALWAYS (2) /
OPEN_ALWAYS (4) values.

Previously, the create_mode field used CreationDisposition which only
accepts values 1-5 via TryFromBytes, causing FileOpen entries with
non-standard modes to silently become Entry::Invalid.

Fix by changing create_mode to I32<LE> (accepts any value) and comparing
by integer in the execution logic.
Signed-off-by: Tom Plant <tom.plant@devicie.com>
The vendored `inno` and `msi` git submodules pointed at commits that no
longer exist on their remotes, so `git submodule update --init` failed and
broke CI checkout. Both crates are available on crates.io at the exact
versions the manifest already declares (inno 0.4.2, msi 0.10.0), so the
`[patch.crates-io]` overrides and submodules are removed in favour of the
published crates. The healthy `winget-types` submodule is left untouched.

Reconciling the lockfile to the published crates surfaced several
pre-existing issues that the broken submodule checkout had been masking:

- inno 0.4.2 has no `PrivilegeLevel::RequireAdmin` variant (that was a
  fork-only addition); drop the arm so it falls through as before.
- msi analysis set the `Installer::switches` field twice (a botched merge of
  the upstream install-location switch and the custom-switch feature); merge
  both into a single `InstallerSwitches` builder.
- `token.rs` matched a `keyring_core::Entry` as if it were an `Option`.
- Remove unused NSIS header imports.
- Add `hide_env_values` to the three `GITHUB_TOKEN` args that were missing it
  so the help-output secrecy test passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XmPAQgcCW15dCnnmKSyWWc
With the submodule checkout fixed, CI's clippy job (which runs with
`RUSTFLAGS=-D warnings`) could finally run and flagged seven pre-existing
lints. None are behavioural changes:

- `collapsible_if` in `prompts` and `html_page` -> let-chains (already used
  elsewhere in the crate; MSRV 1.95 supports them).
- `redundant_closure` in `sourceforge` -> pass the fn directly.
- `unnecessary_map_or` in `vanity_url` -> `Option::is_none_or`.
- `ptr_arg` in `submit_option` -> take `&mut [_]` (callers coerce, and
  `Editor::new` already takes a slice).
- `large_enum_variant` in `ExeType` -> box the 464-byte `InstallShield`
  variant.
- `too_many_arguments` on `AutoUpdate::run_entry` -> `#[allow]`.

Verified with `RUSTFLAGS=-D warnings cargo clippy` on rust 1.96 (matching CI)
and `cargo check` on the 1.95 MSRV; both clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XmPAQgcCW15dCnnmKSyWWc
Detect Indigo Rose Setup Factory installers (e.g. DIALux evo). The setup
stub embeds the `irsetup.exe` run-time, whose assembly manifest carries
`<description>Setup Factory Run-time</description>`, and the builder stamps
`Created with Setup Factory <version>` into the `Comments` version-info
field. Either signal identifies the installer.

Emits an `exe` installer with the `/S` silent switch and populates the
ARP entry from the version info (product name, publisher, version).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012BX4kXe76SvBKY3BySbzRN
The setup stub's version info describes the Setup Factory run-time (and is
often left at the builder's defaults, e.g. ProductName "Setup Factory
Runtime" published by Indigo Rose Corporation), not the packaged
application. The real Apps & Features / uninstall entry (DisplayName,
DisplayVersion, ProductCode, ...) is written by the compiled setup script
inside the payload, which isn't recoverable from the PE.

Emitting DisplayName/Publisher/DisplayVersion from the version info
therefore produced ARP entries that don't match the registry - the real
winget manifests for these packages (e.g. DIAL.DIALux-evo) carry no such
entries. Drop the extraction and emit only the reliably-known fields: the
exe installer type and the /S silent switch. Version info is still read
solely to detect the "Created with Setup Factory" Comments marker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012BX4kXe76SvBKY3BySbzRN

Copy link
Copy Markdown
Member Author

Test results

Ran komac analyze against a range of real Setup Factory installers. All accessible ones are correctly detected as InstallerType: exe with Silent: /S / SilentWithProgress: /S.

Installer Link Detected Arch
DIALux evo https://cdn.dialux.com/evo/DIALux_evo_14_0.exe ✅ exe · /S x86¹
LDraw All-In-One-Installer² https://www.ldraw.org/files/aioi/LDraw_All-In-One-Installer_2023-02_setup_64Bit_v1.exe ✅ exe · /S x64
gloCOM 7.5.0 https://downloads.bicomsystems.com/desktop/glocom/public/7.5.0/glocom/gloCOM-7.5.0.exe ✅ exe · /S x64
Communicator 7.5.0 https://downloads.bicomsystems.com/desktop/glocom/public/7.5.0/communicator/Communicator-7.5.0.exe ✅ exe · /S x64
Safeguard PDF Writer v4 https://downloads.locklizard.com/SafeguardPDFWriter_v4.exe ✅ exe · /S x86
Safeguard PDF Viewer v3 https://downloads.locklizard.com/SafeguardPDFViewer_v3.exe ✅ exe · /S x86
Safeguard PDF Writer Enterprise v5 https://downloads.locklizard.com/SafeguardPDFWriter_Enterprise_v5.exe ✅ exe · /S x86
OutCALL 2.0 https://github.com/bicomsystems/outcall2/releases/download/v2.0/OutCALL-2.0.exe ⚠️ not tested³

Example output (DIALux evo), which matches the shape of the published DIAL.DIALux-evo manifest (exe + Silent: /S):

InstallerType: exe
InstallModes:
- interactive
- silent
- silentWithProgress
InstallerSwitches:
  Silent: /S
  SilentWithProgress: /S

Notes

¹ Architecture is read from the setup stub's PE machine type. DIALux ships a 32-bit stub that installs a 64-bit app, so it reports x86 where the published manifest says x64. This is a pre-existing limitation of exe architecture detection (the payload's target isn't recoverable from the stub) and isn't specific to this change.

² The exact 2023-02 build has been removed from ldraw.org (404). I verified against the current 2026-01 AIOI, which is the same Setup Factory installer family.

³ The OutCALL asset is a GitHub release download. This session's egress policy scopes GitHub to devicie/*, so github.com downloads for other owners are intercepted, and add_repo rejects cross-owner adds. I didn't route around the policy. It's a standard Setup Factory installer and will be handled identically to the others.

On AppsAndFeaturesEntries

An earlier revision of this PR populated DisplayName / Publisher / DisplayVersion from the stub's PE version info. Testing surfaced that this is wrong: gloCOM/Communicator/LDraw leave the stub's version info at the Setup Factory defaults, so they'd have reported DisplayName: Setup Factory Runtime published by Indigo Rose Corporation. Even where authors customise it (DIALux, Locklizard), the version-info values don't equal the registry uninstall keys that AppsAndFeaturesEntries are meant to mirror — the published DIAL.DIALux-evo manifest carries no such entries at all. The detector now emits no ARP data rather than guessing.


Generated by Claude Code

Rather than reading the setup stub's PE version info - which describes the
Setup Factory run-time and is frequently left at the builder's defaults
(e.g. gloCOM/Communicator reported "Setup Factory Runtime" published by
"Indigo Rose Corporation") - walk the Setup Factory 8/9 archive in the PE
overlay to recover the compiled setup script (irsetup.dat) and its session
variable table. That table holds the values the author entered in the
designer: %ProductName%, %CompanyName% and %ProductVer%.

The archive layout and XOR/compression handling follow the format
documented by CybercentreCanada/sfextract. The script is LZMA- or
LZMA2-compressed (decoded via the already-vendored liblzma); large embedded
files are seeked past so only the small script is buffered. Detection now
keys off the 16-byte overlay signature, with the run-time manifest and
version-info comments kept as fallbacks.

The recovered product name and publisher populate AppsAndFeaturesEntries.
The version variable is author-defined and sometimes a bare major number,
so it is only used when it looks like a real dotted version.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012BX4kXe76SvBKY3BySbzRN
@pl4nty Tom Plant (pl4nty) force-pushed the claude/setup-factory-analysis-2yb6iz branch from 884e97d to aca026b Compare July 7, 2026 05:13

Copy link
Copy Markdown
Member Author

Updated results — metadata now parsed from the overlay archive

Following the feedback to parse the binary rather than the stub's PE version info, the detector now walks the Setup Factory archive, decompresses irsetup.dat, and reads the session-variable table. komac analyze output against the real installers:

Installer Link DisplayName Publisher DisplayVersion
DIALux evo https://cdn.dialux.com/evo/DIALux_evo_14_0.exe DIALux DIAL GmbH 5.14.0.4
LDraw AIOI¹ https://www.ldraw.org/files/aioi/LDraw_All-In-One-Installer_2023-02_setup_64Bit_v1.exe LDraw (64 Bit) LDraw.org
gloCOM 7.5.0 https://downloads.bicomsystems.com/desktop/glocom/public/7.5.0/glocom/gloCOM-7.5.0.exe gloCOM Bicom Systems
Communicator 7.5.0 https://downloads.bicomsystems.com/desktop/glocom/public/7.5.0/communicator/Communicator-7.5.0.exe Communicator
Safeguard PDF Writer v4 https://downloads.locklizard.com/SafeguardPDFWriter_v4.exe Locklizard Safeguard - PDF Writer Locklizard Ltd. 4.0.24
Safeguard PDF Viewer v3 https://downloads.locklizard.com/SafeguardPDFViewer_v3.exe Locklizard Safeguard - PDF Viewer Locklizard Ltd. 3.0.2.231
Safeguard PDF Writer Enterprise v5 https://downloads.locklizard.com/SafeguardPDFWriter_Enterprise_v5.exe Locklizard Safeguard - PDF Writer Enterprise Locklizard Ltd. 5.0.46
OutCALL 2.0 https://github.com/bicomsystems/outcall2/releases/download/v2.0/OutCALL-2.0.exe not tested²

All emit InstallerType: exe with Silent: /S. This is a clear improvement over the earlier PE-version-info approach — gloCOM/Communicator previously reported Setup Factory Runtime published by Indigo Rose Corporation; they now show their real names, and LDraw (which had no usable version info) now yields LDraw (64 Bit) / LDraw.org.

Notes

¹ The exact 2023-02 build is gone from ldraw.org (404); verified against the current 2026-01 AIOI, same Setup Factory family. Its %ProductVer% isn't a dotted version, so no DisplayVersion is emitted.

² OutCALL is a GitHub release asset; this session's egress policy scopes GitHub to devicie/* and add_repo rejects cross-owner adds, so it couldn't be downloaded. Not routed around.

On the empty/omitted fields

  • Communicator has no publisher and gloCOM/Communicator no version because those values are genuinely absent or non-versioned in the project (%CompanyName% is empty; %ProductVer% is a bare "4" while the real version sits in a custom variable). %ProductVer% is only used when it looks like a real dotted version, so the bogus "4" is dropped rather than emitted.

Known limitation

Architecture still comes from the setup stub's PE machine type, so DIALux reports x86 (32-bit stub) though the app is 64-bit. Recovering the true target would require decompressing and inspecting a payload binary; left out of scope here.


Generated by Claude Code

}
}

fn has_archive_signature<R: Read + Seek>(reader: &mut R, overlay_start: u64) -> bool {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

if this is only called once, we should inline it

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in 484018c — inlined into new(). (The manifest/comments fallback that also lived in this file is gone too, so detection is now just the inlined signature check.)


Generated by Claude Code

Comment on lines +59 to +66
// The overlay signature is the definitive marker, but fall back to the run-time manifest and
// version-info comments so older (Setup Factory 7) or repacked stubs are still recognised.
if !has_archive
&& !is_runtime_manifest(pe, &mut reader)
&& !has_setup_factory_comments(pe, &mut reader)
{
return Err(SetupFactoryError::NotSetupFactoryFile);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

can we remove this? which of your tests actually needs it? if we're going to keep it, we should document the tests + Factory versions that trigger it

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Removed in 484018c. No test needed it — all seven test installers (DIALux evo, LDraw AIOI, gloCOM, Communicator, and the three Locklizard Safeguard installers) carry the 16-byte overlay signature, so detection now keys off that alone. The fallback was speculative (Setup Factory 7 / repacked stubs) with no coverage.


Generated by Claude Code

//! ..\x0d%ProductName%\x06gloCOM\x01\x00\x00\x00..\x0d%CompanyName%\x0dBicom Systems..
//! ```
//!
//! Entries are separated by a short, version-dependent run of bytes, so rather than decode that

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

is there any documentation or code that could decode these bytes? I wonder if they have useful data

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I dug into these. Between entries the bytes are 01 00 00 00 <XX XX 01> 00 00 00: the leading 01 is a constant type/flag, and the middle three bytes are constant within a given installer but differ between installers (6e 81 01 for Locklizard PDF Writer, b4 83 01 for gloCOM) — i.e. a per-build marker/checksum, not per-variable data. No product metadata is hidden there; the useful content is the name/value pairs we already extract. Neither sfextract nor SFUnpacker decode this table (they only handle the CSetupFileData file table), so there's no reference decoder to borrow from.


Generated by Claude Code


/// A file count above this is treated as an embedded `lua5.1.dll` special file rather than a real
/// count, matching `sfextract`'s heuristic.
const MAX_PLAUSIBLE_FILE_COUNT: u32 = 1000;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

which test cases have this? is the real issue that we're not parsing a specific Factory version properly?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

All seven test installers take this path — it's the normal Setup Factory 9 layout, not a version mis-parse. After irsetup.exe, SF9 embeds a second special file (lua5.1.dll, ~350 KB) before the file table. The u32 read here to disambiguate is the low half of that DLL's 64-bit size (~350000), hence >1000; a genuine file count is small. Expanded the doc comment in 484018c to spell this out.


Generated by Claude Code


/// Upper bound on the decompressed script size we are willing to buffer (scripts are well under a
/// megabyte; this guards against a malformed size field).
const MAX_SCRIPT_SIZE: i64 = 64 << 20;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't think this is necessary

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agreed — removed in 484018c. The script is now read with a bounded take(size).read_to_end(), which grows with the data instead of pre-allocating from the size field, so the cap isn't needed.


Generated by Claude Code

Claude (claude) and others added 5 commits July 7, 2026 23:25
Integrate 31 upstream commits from unpn-org/Komac (anthelion branch)
alongside the existing devicie changes.

Key conflict resolutions:
- CI workflows (audit/build/release): kept devicie's versions (anthelion
  had deleted them).
- serde: kept devicie's serde_yaml + serini stack; reverted anthelion's
  serde-saphyr usage in the shared files while preserving their other
  changes (retry middleware, font support, changed signatures).
- winget-types: switched the [patch.crates-io] source to anthelion's fork
  (UnownPlain/winget-types, anthelion branch) with features
  [serde, std, chrono] and no serde-saphyr, because anthelion's code
  requires API only that fork provides (Velopack/Squirrel installer
  types, LanguageTag accessors, ValidFileExtensions). komac still uses
  serde_yaml. devicie's own winget-types fork carried no meaningful
  custom code (a one-line Cargo.toml tweak plus two upstream PRs).
- github owner/repo: adopted anthelion's configurable EnvStr system but
  kept devicie's pl4nty/winget-extras as the defaults.
- get_versions/get_manifests/get_existing_pull_request/PackagePath:
  threaded anthelion's new font parameters through devicie call sites.
- update_version: preserved devicie's optional package_version + PE
  ProductVersion inference flow; grafted in anthelion's font handling and
  locale normalization.
- Adapted devicie's installer analyzers (installshield/qt return codes,
  autoupdate strategies) to anthelion fork's winget-types API.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LAsaSyfFuR5pcV43kApw5x
- Detect solely from the 16-byte overlay signature and inline the check;
  drop the run-time manifest / version-info comment fallback, which no test
  exercised (all samples carry the signature).
- Read the script with a bounded take().read_to_end() instead of
  pre-allocating from the size field, removing the size-cap guard.
- Document that the embedded lua5.1.dll branch is taken by every tested
  installer (it is the normal Setup Factory 9 layout, not a version
  mis-parse): the leading u32 is the low half of the DLL's 64-bit size.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012BX4kXe76SvBKY3BySbzRN
…on-gijrjb

Merge anthelion changes into devicie fork
…analysis-2yb6iz

# Conflicts:
#	src/analysis/installers/exe.rs
The stable clippy used in CI (1.97) flags the redundant `&` on the
format! arguments in `remove_version`, which fails the `-D warnings`
job after merging the latest main. Drop the borrows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012BX4kXe76SvBKY3BySbzRN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants