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
838fe8b
feat: establish public client contracts and build foundation
AriusII Sep 20, 2026
e688f0e
fix: remediate foundation Sonar findings
AriusII Sep 20, 2026
a968ada
fix: harden foundation contracts and CI review gates
AriusII Sep 20, 2026
7ee7e75
feat: add activation-bound Core runtime
AriusII Sep 20, 2026
34d5163
fix: remediate Core Sonar findings
AriusII Sep 20, 2026
7966554
fix: harden Core review findings
AriusII Sep 20, 2026
ee0e8b3
feat: add immutable Fluent memory and AOB APIs
AriusII Sep 20, 2026
05e3c0c
test: cover Fluent Sonar paths
AriusII Sep 20, 2026
8c43bf3
fix: clarify Fluent memory binding recovery
AriusII Sep 20, 2026
e52e51b
feat: compose Client through DI and plugin Hosting
AriusII Sep 20, 2026
8df393b
fix: remediate DI and Hosting Sonar findings
AriusII Sep 20, 2026
0e70fc2
fix: harden DI activation composition
AriusII Sep 20, 2026
37f5eb5
chore: add delivery pipeline and ceplugin template
AriusII Sep 20, 2026
019814a
ci: publish Sonar coverage
AriusII Sep 20, 2026
afc503a
docs: Dosu updates for PR #6
dosubot[bot] Sep 20, 2026
0547617
fix: harden delivery gates and template cleanup
AriusII Sep 20, 2026
38dba91
Merge pull request #6 from CheatEngineNet/delivery-quality-and-template
AriusII Sep 20, 2026
b746f7e
Merge pull request #4 from CheatEngineNet/client-hosting-and-di
AriusII Sep 20, 2026
68aefac
Merge pull request #3 from CheatEngineNet/client-fluent-api
AriusII Sep 20, 2026
b50146d
Improve client coverage and quality gates
AriusII Sep 20, 2026
c9d83fa
Merge pull request #2 from CheatEngineNet/client-core-runtime
AriusII Sep 20, 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
134 changes: 134 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,11 +1,145 @@
root = true

# Repository-wide, editor-agnostic defaults. Language-specific sections below
# intentionally override these values where a format has stricter constraints.
[*]
charset = utf-8
insert_final_newline = true
indent_style = space
indent_size = 4
tab_width = 4
max_line_length = 120
trim_trailing_whitespace = true

[*.{csproj,props,targets,slnx,config,json,yml,yaml}]
# YAML cannot use tabs for indentation. Keep project and configuration files
# compact and portable even though C# uses tabs below.
indent_style = space
indent_size = 2
tab_width = 2

[*.{cs,csx}]
################################################################################
# C# team contract
#
# Roslyn settings are the portable source of truth: Rider, VS, dotnet format,
# and CI all understand them. Rider-only settings are marked as such.
################################################################################

# Tabs describe logical nesting; spaces are retained solely to align continuations.
indent_style = tab
indent_size = tab
tab_width = 4
csharp_indent_style = tab
csharp_indent_size = 4
csharp_tab_width = 4
csharp_alignment_tab_fill_style = use_spaces

# Make structural boundaries easy to scan.
csharp_new_line_before_open_brace = all
csharp_new_line_before_catch = true
csharp_new_line_before_else = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_between_query_expression_clauses = true
csharp_indent_braces = false
csharp_indent_switch_labels = true
csharp_preserve_single_line_blocks = false
csharp_preserve_single_line_statements = false
csharp_space_after_cast = true
csharp_space_around_binary_operators = before_and_after
csharp_preferred_modifier_order = public, private, protected, internal, file, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, required, volatile, async

# Keep imports and namespaces deterministic and minimise needless nesting.
dotnet_separate_import_directive_groups = true
dotnet_sort_system_directives_first = true
csharp_using_directive_placement = outside_namespace
csharp_style_namespace_declarations = file_scoped

# Prefer syntax that leaves declarations, construction, and contracts visible.
# `var` is statically typed in C#, but explicit types are the repository's
# readability convention whenever the language can express them.
csharp_style_var_for_built_in_types = false
csharp_style_var_when_type_is_apparent = false
csharp_style_var_elsewhere = false
csharp_style_implicit_object_creation_when_type_is_apparent = false
dotnet_style_require_accessibility_modifiers = always
dotnet_style_readonly_field = true
dotnet_style_explicit_tuple_names = true
dotnet_style_predefined_type_for_locals_parameters_members = true
dotnet_style_predefined_type_for_member_access = true
csharp_prefer_braces = true
csharp_style_prefer_top_level_statements = false

# Enforced now: redundant suppressions report genuine noise and remain build
# blockers because Directory.Build.props treats warnings as errors.
dotnet_diagnostic.IDE0079.severity = error

# Migration rules: surface the historical backlog in every Roslyn-aware editor
# and participate in code cleanup without breaking the currently dirty tree.
# Promote these to warning/error in a dedicated cleanup change once the existing
# source has been reformatted and explicit types have been introduced.
dotnet_diagnostic.IDE0007.severity = none
dotnet_diagnostic.IDE0008.severity = suggestion
dotnet_diagnostic.IDE0011.severity = suggestion
dotnet_diagnostic.IDE0033.severity = suggestion
dotnet_diagnostic.IDE0040.severity = suggestion
dotnet_diagnostic.IDE0044.severity = suggestion
# The formatter still follows the tab contract above. Do not flood every open
# legacy file with a formatting diagnostic before the dedicated reformat pass.
dotnet_diagnostic.IDE0055.severity = none
dotnet_diagnostic.IDE0005.severity = suggestion
dotnet_diagnostic.IDE0065.severity = suggestion
dotnet_diagnostic.IDE0090.severity = suggestion
dotnet_diagnostic.IDE0160.severity = none
dotnet_diagnostic.IDE0161.severity = suggestion
dotnet_diagnostic.IDE1006.severity = suggestion

# Rider derives its own "var or explicit type" inspections from the shared
# csharp_style_var_* values. Silence those copies so IDE0008 is the one
# portable diagnostic developers see, rather than reporting each issue twice.
resharper_suggest_var_or_type_built_in_types_highlighting = none
resharper_suggest_var_or_type_simple_types_highlighting = none
resharper_suggest_var_or_type_elsewhere_highlighting = none
resharper_suggest_var_or_type_deconstruction_declarations_highlighting = none

# Rider-specific, live diagnostic. It complements compiler nullable analysis;
# it is deliberately a warning rather than a CI-only, non-portable error.
resharper_possible_null_reference_exception_highlighting = warning

# Naming rules keep public contracts recognisable before a reader opens a type.
dotnet_naming_rule.interfaces_must_be_prefixed_i.severity = suggestion
dotnet_naming_rule.interfaces_must_be_prefixed_i.symbols = interfaces
dotnet_naming_rule.interfaces_must_be_prefixed_i.style = i_pascal_case
dotnet_naming_symbols.interfaces.applicable_kinds = interface
dotnet_naming_style.i_pascal_case.required_prefix = I
dotnet_naming_style.i_pascal_case.capitalization = pascal_case

dotnet_naming_rule.types_must_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_must_be_pascal_case.symbols = types
dotnet_naming_rule.types_must_be_pascal_case.style = pascal_case
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum, delegate
dotnet_naming_style.pascal_case.capitalization = pascal_case

dotnet_naming_rule.non_private_members_must_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_private_members_must_be_pascal_case.symbols = non_private_members
dotnet_naming_rule.non_private_members_must_be_pascal_case.style = pascal_case
dotnet_naming_symbols.non_private_members.applicable_kinds = property, method, event
dotnet_naming_symbols.non_private_members.applicable_accessibilities = public, internal, protected, protected_internal, private_protected

dotnet_naming_rule.private_fields_must_be_underscore_camel_case.severity = suggestion
dotnet_naming_rule.private_fields_must_be_underscore_camel_case.symbols = private_fields
dotnet_naming_rule.private_fields_must_be_underscore_camel_case.style = underscore_camel_case
dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_style.underscore_camel_case.required_prefix = _
dotnet_naming_style.underscore_camel_case.capitalization = camel_case

# IDE0005 requires XML documentation generation to run during a command-line
# build. Shipping projects already enable it; tests and samples intentionally
# retain it as an editor suggestion rather than acquiring build-only XML output.
[libs/**.cs]
dotnet_diagnostic.IDE0005.severity = error

[src/**.cs]
dotnet_diagnostic.IDE0005.severity = error
54 changes: 0 additions & 54 deletions .github/workflows/build.yml

This file was deleted.

171 changes: 171 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
name: Client validation

on:
workflow_call:
inputs:
collect-coverage:
description: Emit Visual Studio XML coverage for the SonarQube Cloud analysis workflow.
type: boolean
default: false

permissions:
contents: read

defaults:
run:
shell: pwsh

env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
MSBUILDDISABLENODEREUSE: true

jobs:
validate:
name: Validate packages, template, and AOT graph
runs-on: windows-latest
timeout-minutes: 35

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false

- name: Install pinned .NET SDK
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
global-json-file: global.json
cache: true
cache-dependency-path: |
**/packages.lock.json
Directory.Packages.props

- name: Restore locked dependency graph
run: dotnet restore CheatEngine.Client.slnx --locked-mode

- name: Build Release
run: dotnet build CheatEngine.Client.slnx --configuration Release --no-restore --warnaserror

- name: Run unit tests through Microsoft Testing Platform
env:
COLLECT_COVERAGE: ${{ inputs.collect-coverage }}
run: |
$projects = @(Get-ChildItem -Path tests -Filter '*.Tests.csproj' -Recurse -File | Sort-Object Name)
if ($projects.Count -eq 0) {
throw 'No *.Tests.csproj project found under tests.'
}

foreach ($project in $projects) {
$results = Join-Path 'artifacts/test-results' $project.BaseName
$options = @(
'--project', $project.FullName,
'--configuration', 'Release',
'--no-build', '--no-restore',
'--report-trx',
'--results-directory', $results,
'--fail-skips', 'on'
)
if ($env:COLLECT_COVERAGE -eq 'true') {
$options += '--coverage', '--coverage-output-format', 'xml', '--coverage-output', 'coverage.xml'
}

dotnet test @options
}

- name: Summarize test results
if: ${{ !cancelled() }}
run: |
$reports = @(Get-ChildItem -Path artifacts/test-results -Filter *.trx -Recurse -File -ErrorAction SilentlyContinue)
if ($reports.Count -eq 0) {
throw 'Microsoft Testing Platform did not produce a TRX test report.'
}

$results = @($reports | ForEach-Object {
([xml](Get-Content -LiteralPath $_.FullName -Raw)).TestRun.Results.UnitTestResult
} | Where-Object { $_ })
$passed = @($results | Where-Object outcome -eq 'Passed').Count
$skipped = @($results | Where-Object outcome -eq 'NotExecuted').Count
$failed = @($results | Where-Object { $_.outcome -notin 'Passed', 'NotExecuted' })

@(
'### Test results',
'',
'| Total | Passed | Failed | Skipped |',
'| ---: | ---: | ---: | ---: |',
"| $($results.Count) | $passed | $($failed.Count) | $skipped |"
) | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8

- name: Upload test results
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-results
path: artifacts/test-results/**/*.trx
if-no-files-found: warn
retention-days: 14

- name: Upload Sonar coverage
if: ${{ inputs.collect-coverage && !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-client
path: artifacts/test-results/*/coverage.xml
if-no-files-found: error
retention-days: 7

- name: Pack and validate public package APIs
run: dotnet pack CheatEngine.Client.slnx --configuration Release --no-build --no-restore

- name: Smoke test isolated package consumption
shell: pwsh
run: ./eng/Invoke-PackageSmoke.ps1 -PackageSource ./artifacts/packages

- name: Smoke test local template installation
run: ./eng/Invoke-TemplateSmoke.ps1 -PackageSource ./artifacts/packages

- name: Upload package artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: nuget-packages
path: |
artifacts/packages/*.nupkg
artifacts/packages/*.snupkg
if-no-files-found: error
retention-days: 14

- name: Publish Native AOT reference probe
run: dotnet publish tests/CheatEngine.Client.AotProbe/CheatEngine.Client.AotProbe.csproj --configuration Release --runtime win-x64 --no-restore --output ./artifacts/aot-probe

- name: Run Native AOT reference probe
run: ./artifacts/aot-probe/CheatEngine.Client.AotProbe.exe

- name: Upload Native AOT probe
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: native-aot-probe
path: artifacts/aot-probe
if-no-files-found: warn
retention-days: 14

gate:
name: Gate
if: ${{ always() }}
needs: validate
runs-on: windows-latest
timeout-minutes: 5
permissions: {}

steps:
- name: Check validation result
env:
VALIDATE_RESULT: ${{ needs.validate.result }}
run: |
"| Job | Result |", "| --- | --- |", "| validate | $env:VALIDATE_RESULT |" |
Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
if ($env:VALIDATE_RESULT -ne 'success') {
Write-Host "::error::Validation finished with '$env:VALIDATE_RESULT'."
exit 1
}
Loading