Skip to content

feat: Get-OffsetSignature (Authenticode provenance); strip long dashes - 3.3.0 - #21

Merged
warpedatom merged 3 commits into
mainfrom
release/3.3.0
Jul 28, 2026
Merged

feat: Get-OffsetSignature (Authenticode provenance); strip long dashes - 3.3.0#21
warpedatom merged 3 commits into
mainfrom
release/3.3.0

Conversation

@warpedatom

@warpedatom warpedatom commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary by Sourcery

Add Authenticode provenance verification to OffsetInspect and release it as version 3.3.0.

New Features:

  • Introduce Get-OffsetSignature to report a file's Authenticode signature validity, trust status, signer identity, and signing kind as OffsetInspect.SignatureInfo on Windows.

Enhancements:

  • Shape raw Authenticode signature data into a normalized OffsetInspect.SignatureInfo object for consistent provenance reporting.
  • Expose the new Get-OffsetSignature command in the module manifest, exports, and metadata, including a new Authenticode tag and 3.3.0 release notes.

Documentation:

  • Document the new Get-OffsetSignature command, its purpose, and the SignatureInfo schema in the README and OUTPUT-SCHEMA, and update the changelog for the 3.3.0 release while normalizing dash usage in existing docs.

Tests:

  • Add unit tests for Authenticode signature shaping and a Windows-only end-to-end test for Get-OffsetSignature, and update module tests to expect the new public command and version 3.3.0.

@sourcery-ai

sourcery-ai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Implements a new Windows-only Authenticode provenance feature centered around the public Get-OffsetSignature cmdlet and its OffsetInspect.SignatureInfo output type, wires it into the module manifest/exports, adds unit and end-to-end tests for signature shaping, bumps the module to v3.3.0, and updates README/CHANGELOG/docs to document the new command and normalize dash usage.

Sequence diagram for Get-OffsetSignature Authenticode verification flow

sequenceDiagram
    actor User
    participant Get_OffsetSignature
    participant Test_OIIsWindows
    participant Get_AuthenticodeSignature
    participant ConvertTo_OISignatureInfo

    User->>Get_OffsetSignature: Get-OffsetSignature FilePath
    Get_OffsetSignature->>Test_OIIsWindows: Test-OIIsWindows
    Test_OIIsWindows-->>Get_OffsetSignature: isWindows
    alt [not Windows]
        Get_OffsetSignature-->>User: throw "requires Windows"
    else [Windows]
        Get_OffsetSignature->>Get_OffsetSignature: Resolve-Path / Get-Item
        Get_OffsetSignature->>Get_AuthenticodeSignature: Get-AuthenticodeSignature LiteralPath
        Get_AuthenticodeSignature-->>Get_OffsetSignature: Signature
        Get_OffsetSignature->>ConvertTo_OISignatureInfo: ConvertTo-OISignatureInfo Signature File FileSize
        ConvertTo_OISignatureInfo-->>Get_OffsetSignature: SignatureInfo
        Get_OffsetSignature-->>User: OffsetInspect.SignatureInfo
    end
Loading

File-Level Changes

Change Details Files
Add Windows-only Authenticode signature inspection pipeline and public Get-OffsetSignature cmdlet.
  • Introduce private Threat.Signature.ps1 with helpers Get-OIMemberValue and Get-OICommonName, plus pure converter ConvertTo-OISignatureInfo that shapes Get-AuthenticodeSignature results into OffsetInspect.SignatureInfo in a StrictMode-safe, cross-version-compatible way.
  • Add public Get-OffsetSignature cmdlet that validates Windows-only execution, resolves and validates the target file, calls Get-AuthenticodeSignature, and returns the shaped OffsetInspect.SignatureInfo object including file size.
  • Mark OffsetInspect.SignatureInfo objects with a dedicated type name and ensure properties cover signature validity, signer identity, catalog vs embedded, OS-binary flag, timestamping, and warnings.
module/OffsetInspect/Private/Threat.Signature.ps1
module/OffsetInspect/Public/Get-OffsetSignature.ps1
Wire new signature feature into module packaging, exports, and tests, and bump version to 3.3.0.
  • Update module manifest to version 3.3.0, include Threat.Signature.ps1 in PrivateData ScriptsToProcess (or equivalent), include Get-OffsetSignature.ps1 in FunctionsToExport/ScriptsToProcess, add Authenticode to tags, and add release notes for the 3.3.0 feature.
  • Export Get-OffsetSignature from OffsetInspect.psm1 so the cmdlet is publicly available.
  • Extend OffsetInspect.Tests.ps1 to assert the manifest version is 3.3.0, ensure Get-OffsetSignature appears in the set of exported public commands, add unit tests for ConvertTo-OISignatureInfo covering valid catalog-signed, unsigned, invalid-but-present signatures, and expired signer cases, and add a Windows-only end-to-end test against a real system binary using Get-OffsetSignature.
module/OffsetInspect/OffsetInspect.psd1
module/OffsetInspect/OffsetInspect.psm1
tests/OffsetInspect.Tests.ps1
Document the new Authenticode provenance feature and its schema and integrate it into the high-level feature set.
  • Update README to describe Get-OffsetSignature as a first-class feature in the bullet list, command summary table, and examples, including positioning it alongside imphash/Rich-header provenance and marking it Windows-only.
  • Extend CHANGELOG with a 3.3.0 entry describing Get-OffsetSignature, its semantics, platform limitation, and relationship to OffsetScan 0.4.0 Rich-header support.
  • Add OffsetInspect.SignatureInfo to OUTPUT-SCHEMA.md with a property table explaining each field and the Windows-only nature of the object.
  • Clarify related design/docs where needed (e.g., telemetry and provider docs) to maintain consistent narrative about Windows-only providers and provenance.
README.md
CHANGELOG.md
docs/OUTPUT-SCHEMA.md
docs/TELEMETRY-CORRELATION-DESIGN.md
docs/PROVIDER-INTERFACE.md
Normalize prose dash usage across docs and metadata to use simple hyphen-minus plus spaces instead of long dashes.
  • Replace em dashes and similar long-dash punctuation with " - " in README sections describing features, options, and explanatory clauses.
  • Apply the same dash normalization to CHANGELOG entries, output-schema docs, telemetry design doc, provider interface, and the code of conduct where narrative text previously used long dashes for asides or ranges.
README.md
CHANGELOG.md
docs/OUTPUT-SCHEMA.md
docs/TELEMETRY-CORRELATION-DESIGN.md
docs/PROVIDER-INTERFACE.md
Code_of_Conduct.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="module/OffsetInspect/Private/Threat.Signature.ps1" line_range="25-36" />
<code_context>
+    [CmdletBinding()]
+    param([AllowNull()][string]$DistinguishedName)
+    if ([string]::IsNullOrWhiteSpace($DistinguishedName)) { return $null }
+    foreach ($part in $DistinguishedName -split ',') {
+        $trimmed = $part.Trim()
+        if ($trimmed -match '^CN=(.+)$') { return $Matches[1].Trim() }
</code_context>
<issue_to_address>
**suggestion:** Distinguished name parsing may break on escaped commas or differently formatted DNs.

Splitting on a plain comma will misparse DNs with escaped commas (e.g. `CN=Example\, Inc.,O=Example`). If those are possible, use `System.Security.Cryptography.X509Certificates.X500DistinguishedName` (`Decode` with appropriate `X500DistinguishedNameFlags`) to extract CN, or at least use a DN-aware parsing approach instead of a raw `-split ','`.

```suggestion
function Get-OICommonName {
    # Pull the CN (common name) out of an X.500 subject/issuer for a readable label, falling
    # back to the full distinguished name.
    [CmdletBinding()]
    param([AllowNull()][string]$DistinguishedName)

    if ([string]::IsNullOrWhiteSpace($DistinguishedName)) { return $null }

    # Prefer DN-aware parsing via X500DistinguishedName to handle escaped commas and formatting
    try {
        $dnObject = [System.Security.Cryptography.X509Certificates.X500DistinguishedName]::new($DistinguishedName)
        $decoded = $dnObject.Decode(
            [System.Security.Cryptography.X509Certificates.X500DistinguishedNameFlags]::UseNewLines
        )

        if (-not [string]::IsNullOrWhiteSpace($decoded)) {
            foreach ($line in $decoded -split "`n") {
                $trimmed = $line.Trim()
                if ($trimmed -match '^CN=(.+)$') {
                    return $Matches[1].Trim()
                }
            }
        }
    }
    catch {
        # Fall through to the simple fallback below on invalid or unparsable DNs
    }

    # Fallback: if we couldn't parse via X500DistinguishedName, return the original DN trimmed
    return $DistinguishedName.Trim()
}
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +25 to +36
function Get-OICommonName {
# Pull the CN (common name) out of an X.500 subject/issuer for a readable label, falling
# back to the full distinguished name.
[CmdletBinding()]
param([AllowNull()][string]$DistinguishedName)
if ([string]::IsNullOrWhiteSpace($DistinguishedName)) { return $null }
foreach ($part in $DistinguishedName -split ',') {
$trimmed = $part.Trim()
if ($trimmed -match '^CN=(.+)$') { return $Matches[1].Trim() }
}
return $DistinguishedName.Trim()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Distinguished name parsing may break on escaped commas or differently formatted DNs.

Splitting on a plain comma will misparse DNs with escaped commas (e.g. CN=Example\, Inc.,O=Example). If those are possible, use System.Security.Cryptography.X509Certificates.X500DistinguishedName (Decode with appropriate X500DistinguishedNameFlags) to extract CN, or at least use a DN-aware parsing approach instead of a raw -split ','.

Suggested change
function Get-OICommonName {
# Pull the CN (common name) out of an X.500 subject/issuer for a readable label, falling
# back to the full distinguished name.
[CmdletBinding()]
param([AllowNull()][string]$DistinguishedName)
if ([string]::IsNullOrWhiteSpace($DistinguishedName)) { return $null }
foreach ($part in $DistinguishedName -split ',') {
$trimmed = $part.Trim()
if ($trimmed -match '^CN=(.+)$') { return $Matches[1].Trim() }
}
return $DistinguishedName.Trim()
}
function Get-OICommonName {
# Pull the CN (common name) out of an X.500 subject/issuer for a readable label, falling
# back to the full distinguished name.
[CmdletBinding()]
param([AllowNull()][string]$DistinguishedName)
if ([string]::IsNullOrWhiteSpace($DistinguishedName)) { return $null }
# Prefer DN-aware parsing via X500DistinguishedName to handle escaped commas and formatting
try {
$dnObject = [System.Security.Cryptography.X509Certificates.X500DistinguishedName]::new($DistinguishedName)
$decoded = $dnObject.Decode(
[System.Security.Cryptography.X509Certificates.X500DistinguishedNameFlags]::UseNewLines
)
if (-not [string]::IsNullOrWhiteSpace($decoded)) {
foreach ($line in $decoded -split "`n") {
$trimmed = $line.Trim()
if ($trimmed -match '^CN=(.+)$') {
return $Matches[1].Trim()
}
}
}
}
catch {
# Fall through to the simple fallback below on invalid or unparsable DNs
}
# Fallback: if we couldn't parse via X500DistinguishedName, return the original DN trimmed
return $DistinguishedName.Trim()
}

@warpedatom
warpedatom merged commit 4e08e12 into main Jul 28, 2026
7 checks passed
@warpedatom
warpedatom deleted the release/3.3.0 branch July 28, 2026 03:52
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.

1 participant