Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ jobs:
- name: Installer detection regression checks
shell: pwsh
run: ./installer/checks/Test-Detection.ps1
- name: Release Defender activation contract checks (isolated mocks)
shell: pwsh
run: ./scripts/checks/Test-ReleaseDefender.ps1
- name: Verify Defender activation on hosted runner
shell: pwsh
run: |
./scripts/Enable-ReleaseDefender.ps1
./scripts/Check-ReleaseArtifacts.ps1 -Paths @('ClaudeRevit/bin/Release/release/ClaudeRevit.dll') -ReportPath defender-ci.json -SourceCommit '${{ github.sha }}'
- name: Upload Revit 2027 build
uses: actions/upload-artifact@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ jobs:
- name: Scan release payloads and final packages
shell: pwsh
run: |
Update-MpSignature -ErrorAction Stop
./scripts/Enable-ReleaseDefender.ps1
$targets = @((Resolve-Path 'installer/payload').Path)
$targets += Get-ChildItem "ClaudeRevit-${{ steps.vars.outputs.version }}-Revit*.zip" | ForEach-Object FullName
$targets += '${{ steps.installer.outputs.path }}'
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ MCP agents: choose **Claude Code · MCP** or **Codex · MCP**, then select a mod
and reasoning effort. Choices are saved independently. Codex reads its model
catalog from the installed CLI. See [agent selection and setup](docs/openai-codex.md).

**v3.8.4:** mandatory objective benchmark checks, repeated-run calibration, channel/angle/tube/paired-timber sections, dependent nodes and actual bore checks, multicategory live SPDS sources, optional verified experience and saved resumable jobs. Seven generated sections, shared nesting, checkpoint recovery, dependent nodes, live steel/timber quantities and eight BIMStarter references have now been exercised in Revit. [Executed results and limits](docs/native-acceptance-2026-10.md) · [Release notes](docs/releases/v3.8.4.md) · [BIMStarter findings](docs/bimstarter-reference-cases.md).
**v3.8.5:** mandatory objective benchmark checks, repeated-run calibration, channel/angle/tube/paired-timber sections, dependent nodes and actual bore checks, multicategory live SPDS sources, optional verified experience and saved resumable jobs. Seven generated sections, shared nesting, checkpoint recovery, dependent nodes, live steel/timber quantities and eight BIMStarter references have now been exercised in Revit. Includes the release-runner Defender activation fix after v3.8.4 publication was blocked. [Executed results and limits](docs/native-acceptance-2026-10.md) · [Release notes](docs/releases/v3.8.5.md) · [BIMStarter findings](docs/bimstarter-reference-cases.md).

**v3.8.3:** live SPDS steel/timber schedules, native steel connection inspection, persistent keyed nodes and geometry-driving parametric sections with independent flex checks. Instance values survive type changes; compiler/worker failures and timing are journaled. Code execution is always enabled, with no permission checkbox. [Structural workflows and limits](docs/structural-workflows.md) · [Release notes](docs/releases/v3.8.3.md).

Expand Down
2 changes: 1 addition & 1 deletion README.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
глубину рассуждений. Настройки агентов сохраняются отдельно; Codex получает
список моделей из установленного CLI. [Выбор агента и настройка](docs/openai-codex.md).

**v3.8.4:** обязательные объективные проверки бенчмарка, повторы и калибровка времени, швеллер/уголок/труба/парное деревянное сечение, зависимости узлов и проверка реальных отверстий, живые таблицы нескольких категорий, необязательный проверенный опыт и возобновляемые задания. В Revit проверены семь созданных сечений, вложенность, восстановление заданий, зависимости узлов, обновление стальных/деревянных таблиц и восемь семейств BIMStarter. [Результаты и ограничения](docs/native-acceptance-2026-10.md) · [Изменения](docs/releases/v3.8.4.md) · [Разбор семейств BIMStarter](docs/bimstarter-reference-cases.md).
**v3.8.5:** обязательные объективные проверки бенчмарка, повторы и калибровка времени, швеллер/уголок/труба/парное деревянное сечение, зависимости узлов и проверка реальных отверстий, живые таблицы нескольких категорий, необязательный проверенный опыт и возобновляемые задания. В Revit проверены семь созданных сечений, вложенность, восстановление заданий, зависимости узлов, обновление стальных/деревянных таблиц и восемь семейств BIMStarter. Добавлено включение Defender на сервере сборки: публикация v3.8.4 была остановлена проверкой безопасности. [Результаты и ограничения](docs/native-acceptance-2026-10.md) · [Изменения](docs/releases/v3.8.5.md) · [Разбор семейств BIMStarter](docs/bimstarter-reference-cases.md).

**v3.8.3:** живые спецификации СПДС для стали и дерева, проверка загруженных нативных стальных соединений, сохраняемые узлы с адресным обновлением и параметрические сечения с независимыми flex-проверками. Параметры экземпляра сохраняются при смене типа; журнал отдельно учитывает компиляцию и её ошибки. Выполнение кода доступно всегда, переключатель разрешения удалён. [Инструменты и ограничения](docs/structural-workflows.md) · [Релиз](docs/releases/v3.8.3.md).

Expand Down
9 changes: 9 additions & 0 deletions docs/installer-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,12 @@ archive contents and exclusions are handled by the scanner without changing
real-time protection or restoring files. See the
[official command reference](https://learn.microsoft.com/en-us/defender-endpoint/command-line-arguments-microsoft-defender-antivirus).
A passing scan is a time-specific result from one engine, not a safety guarantee.

GitHub's [Windows image configuration](https://github.com/actions/runner-images/blob/main/images/windows/scripts/build/Configure-WindowsDefender.ps1)
disables monitoring and can force passive mode. The first v3.8.4 release attempt
built every package but failed closed at this gate; nothing was published.
`Enable-ReleaseDefender.ps1` now activates protection only on a disposable hosted
Windows runner, removes that image's two whole-drive exclusions and updates
intelligence. It follows Microsoft's [always-on protection settings](https://learn.microsoft.com/en-us/defender-endpoint/configure-real-time-protection-microsoft-defender-antivirus).
Developer-machine invocation is rejected. Activation failure still blocks release;
the original scan gate is retained. Isolated contract tests mock all system calls.
7 changes: 7 additions & 0 deletions docs/releases/v3.8.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# v3.8.5 — verified modeling and checked release packaging

Includes all [v3.8.4 modeling changes](https://github.com/debug23win/ClaudeRevit/blob/main/docs/releases/v3.8.4.md): objective benchmark evidence, repeated-run calibration, seven constrained section shapes, dependent nodes/bore inspection, live multicategory SPDS summaries, optional verified experience and saved checkpoint jobs. See [executed native results and limits](https://github.com/debug23win/ClaudeRevit/blob/main/docs/native-acceptance-2026-10.md).

The v3.8.4 build completed, but publication was blocked because GitHub's Windows image had Defender inactive. This patch activates it only on the disposable hosted runner, removes its whole-drive exclusions, updates intelligence and retains the mandatory scan of payloads, final ZIPs and the exact installer. Activation, detection or scan failures still block release. No developer-computer security settings are changed.

215 unit tests and WPF/MCP/subscription CLI/installer checks passed. Native Revit 2027 cases cover generated sections, shared nesting, recovery, dependent-node edits, bores, eight BIMStarter references and live steel/timber quantities. Reference visibility variants and generated structural-template placement remain bounded as described in the acceptance report. Steel summaries are separate live grouped schedules, not an exact single-table form 2 facsimile; agree formatting before issuing drawings.
3 changes: 2 additions & 1 deletion scripts/Check-ReleaseArtifacts.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ param(
# Fail closed. A successful scan is evidence from one engine at one time, not a
# guarantee of safety. Do not add exclusions, restore quarantine or disable AV.
$ErrorActionPreference = 'Stop'
$report = [ordered]@{ source_commit = $SourceCommit; utc = [DateTime]::UtcNow.ToString('o'); status = 'incomplete'; engine = $null; files = @(); error = $null }
$report = [ordered]@{ source_commit = $SourceCommit; utc = [DateTime]::UtcNow.ToString('o'); status = 'incomplete'; protection = $null; engine = $null; files = @(); error = $null }
try {
$status = Get-MpComputerStatus -ErrorAction Stop
$report.protection = @{ mode = $status.AMRunningMode; antivirus_enabled = [bool]$status.AntivirusEnabled; realtime_enabled = [bool]$status.RealTimeProtectionEnabled }
if (-not $status.AntivirusEnabled -or -not $status.RealTimeProtectionEnabled) {
throw 'Microsoft Defender must be active; release scanning cannot be skipped.'
}
Expand Down
25 changes: 25 additions & 0 deletions scripts/Enable-ReleaseDefender.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# GitHub's disposable Windows images disable monitoring and can force passive mode.
# Strengthen that runner before packaging; never change a developer's AV settings.
$ErrorActionPreference = 'Stop'
if ($env:GITHUB_ACTIONS -ne 'true' -or $env:RUNNER_OS -ne 'Windows' -or $env:RUNNER_ENVIRONMENT -ne 'github-hosted') {
throw 'Defender activation is restricted to disposable GitHub-hosted Windows runners.'
}
$policy = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows Advanced Threat Protection'
if (Test-Path -LiteralPath $policy) {
Set-ItemProperty -LiteralPath $policy -Name ForceDefenderPassiveMode -Value 0 -Type DWord
}
Start-Service -Name WinDefend -ErrorAction Stop
Set-MpPreference -DisableRealtimeMonitoring $false -DisableBehaviorMonitoring $false -DisableArchiveScanning $false -DisableScriptScanning $false -DisableIOAVProtection $false -ErrorAction Stop
# Remove only the two whole-drive exclusions supplied by the runner image.
$broadExclusions = @((Get-MpPreference).ExclusionPath | Where-Object { $_ -in @('C:\','D:\') })
if ($broadExclusions.Count) { Remove-MpPreference -ExclusionPath $broadExclusions -ErrorAction Stop }
Update-MpSignature -ErrorAction Stop
for ($attempt = 0; $attempt -lt 12; $attempt++) {
$status = Get-MpComputerStatus -ErrorAction Stop
if ($status.AntivirusEnabled -and $status.RealTimeProtectionEnabled) {
$status | Select-Object AMRunningMode, AntivirusEnabled, RealTimeProtectionEnabled, AntivirusSignatureVersion
return
}
Start-Sleep -Seconds 2
}
throw 'Defender activation failed; release publication remains blocked.'
31 changes: 31 additions & 0 deletions scripts/checks/Test-ReleaseDefender.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Isolated contract checks: mocks never change AV, services, registry or network.
$ErrorActionPreference = 'Stop'
$activationScript = Join-Path $PSScriptRoot '..\Enable-ReleaseDefender.ps1'
$original = @{}
foreach ($name in @('GITHUB_ACTIONS','RUNNER_OS','RUNNER_ENVIRONMENT')) { $original[$name] = [Environment]::GetEnvironmentVariable($name) }
function Assert($condition, $message) { if (-not $condition) { throw $message } }
try {
$env:GITHUB_ACTIONS = 'false'
try { & $activationScript; throw 'Local invocation was allowed' }
catch { Assert ($_.Exception.Message -like '*restricted to disposable*') 'Local guard failed' }
$qaMock=@{}
function Test-Path { param($LiteralPath) return $true }
function Set-ItemProperty { param($LiteralPath,$Name,$Value,$Type) Assert ($Name -eq 'ForceDefenderPassiveMode' -and $Value -eq 0) 'Policy must enable active mode'; $qaMock.policyWrites++ }
function Start-Service { [CmdletBinding()]param($Name) Assert ($Name -eq 'WinDefend') 'Unexpected service'; $qaMock.serviceStarts++ }
function Set-MpPreference { [CmdletBinding()]param($DisableRealtimeMonitoring,$DisableBehaviorMonitoring,$DisableArchiveScanning,$DisableScriptScanning,$DisableIOAVProtection) Assert (-not ($DisableRealtimeMonitoring -or $DisableBehaviorMonitoring -or $DisableArchiveScanning -or $DisableScriptScanning -or $DisableIOAVProtection)) 'Protection was weakened'; $qaMock.preferenceWrites++ }
function Get-MpPreference { return @{ExclusionPath=@('C:\','D:\','C:\retained-example')} }
function Remove-MpPreference { [CmdletBinding()]param($ExclusionPath) Assert (($ExclusionPath -join ',') -eq 'C:\,D:\') 'Only runner whole-drive exclusions may be removed'; $qaMock.exclusionRemovals++ }
function Update-MpSignature { [CmdletBinding()]param() $qaMock.signatureUpdates++ }
function Get-MpComputerStatus { [CmdletBinding()]param() $qaMock.statusReads++; return @{ AntivirusEnabled=$qaMock.ready; RealTimeProtectionEnabled=$qaMock.ready } }
function Start-Sleep { param($Seconds) $qaMock.waits++ }
$env:GITHUB_ACTIONS='true'; $env:RUNNER_OS='Windows'; $env:RUNNER_ENVIRONMENT='github-hosted'
$qaMock.policyWrites=0; $qaMock.serviceStarts=0; $qaMock.preferenceWrites=0; $qaMock.exclusionRemovals=0; $qaMock.signatureUpdates=0; $qaMock.statusReads=0; $qaMock.waits=0; $qaMock.ready=$true
& $activationScript | Out-Null
Assert ($qaMock.policyWrites -eq 1 -and $qaMock.serviceStarts -eq 1 -and $qaMock.preferenceWrites -eq 1 -and $qaMock.exclusionRemovals -eq 1 -and $qaMock.signatureUpdates -eq 1 -and $qaMock.statusReads -eq 1) 'Ready scanner was not verified'
$qaMock.ready=$false; $qaMock.statusReads=0; $qaMock.waits=0
try { & $activationScript | Out-Null; throw 'Inactive scanner was accepted' }
catch { Assert ($_.Exception.Message -like '*publication remains blocked*') 'Inactive scanner did not fail closed' }
Assert ($qaMock.statusReads -eq 12 -and $qaMock.waits -eq 12) 'Activation wait must be bounded'
Write-Output 'RELEASE_DEFENDER_CHECKS_PASSED'
}
finally { foreach ($name in $original.Keys) { [Environment]::SetEnvironmentVariable($name,$original[$name]) } }
Loading