Compare commits

..

6 Commits

Author SHA1 Message Date
copilot-swe-agent[bot] da9911051e fix: use 0-based byte offset in ps1 encoding test failure message 2026-05-26 18:26:25 +00:00
copilot-swe-agent[bot] 07cde6764a Initial plan 2026-05-26 18:25:12 +00:00
Copilot c7e0cacaff fix: PS 5.1 compat — replace non-ASCII chars in shipped PowerShell scripts (#2709)
* Initial plan

* fix: replace non-ASCII chars in PS1 files, add encoding regression tests, fix ANSI stripping in tests, update docs

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-05-26 13:18:34 -05:00
Thorsten Hindermann 0f9beabca7 docs: update security-governance preset to v0.3.0 (#2676) 2026-05-26 12:40:15 -05:00
Davit Mnatobishvili 69b9348776 Update README.md (#2675) 2026-05-26 11:04:22 -05:00
Manfred Riem c47f334629 chore: release 0.8.14, begin 0.8.15.dev0 development (#2706)
* chore: bump version to 0.8.14

* chore: begin 0.8.15.dev0 development

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-26 09:19:56 -05:00
13 changed files with 102 additions and 33 deletions
+2 -2
View File
@@ -35,7 +35,7 @@
- [🔧 Prerequisites](#-prerequisites)
- [📖 Learn More](#-learn-more)
- [📋 Detailed Process](#-detailed-process)
- [ Support](#-support)
- [💬 Support](#-support)
- [🙏 Acknowledgements](#-acknowledgements)
- [📄 License](#-license)
@@ -581,7 +581,7 @@ Once the implementation is complete, test the application and resolve any runtim
---
## Support
## 💬 Support
For support, please open a [GitHub issue](https://github.com/github/spec-kit/issues/new). We welcome bug reports, feature requests, and questions about using Spec-Driven Development.
+1 -1
View File
@@ -23,7 +23,7 @@ The following community-contributed presets customize how Spec Kit behaves — o
| Multi-Repo Branching | Coordinates feature branch creation across multiple git repositories (independent repos and submodules) during plan and tasks phases | 2 commands | — | [spec-kit-preset-multi-repo-branching](https://github.com/sakitA/spec-kit-preset-multi-repo-branching) |
| Pirate Speak (Full) | Transforms all Spec Kit output into pirate speak — specs become "Voyage Manifests", plans become "Battle Plans", tasks become "Crew Assignments" | 6 templates, 9 commands | — | [spec-kit-presets](https://github.com/mnriem/spec-kit-presets) |
| Screenwriting | Spec-Driven Development for screenwriting/scriptwriting/tutorials: feature films, television (pilot, episode, limited series), and stage plays. Adapts the Spec Kit workflow to screenplay craft — slug lines, action lines, act breaks, beat sheets, and industry-standard pitch documents. Supports three-act, Save the Cat, TV pilot, network episode, cable/streaming episode, and stage-play structural frameworks. Export to Fountain, FTX, PDF | 26 templates, 32 commands, 1 script | — | [speckit-preset-screenwriting](https://github.com/adaumann/speckit-preset-screenwriting) |
| Security Governance | Adds secure development governance: memory-safe-language preference, secure code generation, NIST SSDF, CWE Top 25, OWASP ASVS, SBOM/VEX/SLSA, OpenSSF Scorecard, and EU CRA applicability | 12 templates, 3 commands | — | [spec-kit-preset-security-governance](https://github.com/hindermath/spec-kit-preset-security-governance) |
| Security Governance | Adds secure development governance: memory-safe-language preference, secure code generation, NIST SSDF, CWE Top 25, OWASP ASVS, SBOM/AI-SBOM, VEX/SLSA, OpenSSF Scorecard, G7/BSI AI-SBOM target evidence, and EU CRA applicability | 12 templates, 3 commands | — | [spec-kit-preset-security-governance](https://github.com/hindermath/spec-kit-preset-security-governance) |
| Spec2Cloud | Spec-driven workflow tuned for shipping to Azure: spec → plan → tasks → implement → deploy | 5 templates, 8 commands | — | [spec2cloud](https://github.com/Azure-Samples/Spec2Cloud) |
| Table of Contents Navigation | Adds a navigable Table of Contents to generated spec.md, plan.md, and tasks.md documents | 3 templates, 3 commands | — | [spec-kit-preset-toc-navigation](https://github.com/Quratulain-bilal/spec-kit-preset-toc-navigation) |
| VS Code Ask Questions | Enhances the clarify command to use `vscode/askQuestions` for batched interactive questioning. | 1 command | — | [spec-kit-presets](https://github.com/fdcastel/spec-kit-presets) |
@@ -35,7 +35,7 @@ Replace the script to add project-specific Git initialization steps:
## Output
On success:
- ` Git repository initialized`
- `[OK] Git repository initialized`
## Graceful Degradation
@@ -115,7 +115,7 @@ if (Test-Path $configFile) {
}
}
} else {
# No config file auto-commit disabled by default
# No config file -- auto-commit disabled by default
exit 0
}
@@ -1,6 +1,6 @@
#!/usr/bin/env pwsh
# Git-specific common functions for the git extension.
# Extracted from scripts/powershell/common.ps1 contains only git-specific
# Extracted from scripts/powershell/common.ps1 -- contains only git-specific
# branch validation and detection logic.
function Test-HasGit {
@@ -1,7 +1,7 @@
#!/usr/bin/env pwsh
# Git extension: initialize-repo.ps1
# Initialize a Git repository with an initial commit.
# Customizable replace this script to add .gitignore templates,
# Customizable -- replace this script to add .gitignore templates,
# default branch config, git-flow, LFS, signing, etc.
$ErrorActionPreference = 'Stop'
@@ -66,4 +66,4 @@ try {
exit 1
}
Write-Host " Git repository initialized"
Write-Host "[OK] Git repository initialized"
+15 -6
View File
@@ -1,6 +1,6 @@
{
"schema_version": "1.0",
"updated_at": "2026-05-05T10:00:00Z",
"updated_at": "2026-05-22T00:00:00Z",
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.community.json",
"presets": {
"a11y-governance": {
@@ -472,11 +472,11 @@
"security-governance": {
"name": "Security Governance",
"id": "security-governance",
"version": "0.2.0",
"description": "Adds secure development governance, MSL preference, ASVS verification, supply-chain transparency, and EU CRA awareness.",
"version": "0.3.0",
"description": "Adds memory-safe-language preference, secure code generation, ASVS verification, SBOM/AI-SBOM supply-chain transparency, and EU Cyber Resilience Act awareness.",
"author": "Thorsten Hindermann",
"repository": "https://github.com/hindermath/spec-kit-preset-security-governance",
"download_url": "https://github.com/hindermath/spec-kit-preset-security-governance/archive/refs/tags/v0.2.0.zip",
"download_url": "https://github.com/hindermath/spec-kit-preset-security-governance/archive/refs/tags/v0.3.0.zip",
"homepage": "https://github.com/hindermath/spec-kit-preset-security-governance",
"documentation": "https://github.com/hindermath/spec-kit-preset-security-governance/blob/main/README.md",
"license": "MIT",
@@ -491,11 +491,20 @@
"security",
"governance",
"msl",
"ssdf",
"asvs",
"supply-chain"
"supply-chain",
"sbom",
"ai-sbom",
"vex",
"slsa",
"cwe-top-25",
"g7",
"bsi",
"cra"
],
"created_at": "2026-04-27T00:00:00Z",
"updated_at": "2026-04-27T00:00:00Z"
"updated_at": "2026-05-22T00:00:00Z"
},
"spec2cloud": {
"name": "Spec2Cloud",
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "specify-cli"
version = "0.8.14"
version = "0.8.15.dev0"
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
requires-python = ">=3.11"
dependencies = [
+5 -5
View File
@@ -336,10 +336,10 @@ function Get-FeaturePathsEnv {
function Test-FileExists {
param([string]$Path, [string]$Description)
if (Test-Path -Path $Path -PathType Leaf) {
Write-Output " $Description"
Write-Output " [OK] $Description"
return $true
} else {
Write-Output " $Description"
Write-Output " [FAIL] $Description"
return $false
}
}
@@ -347,10 +347,10 @@ function Test-FileExists {
function Test-DirHasFiles {
param([string]$Path, [string]$Description)
if ((Test-Path -Path $Path -PathType Container) -and (Get-ChildItem -Path $Path -ErrorAction SilentlyContinue | Where-Object { -not $_.PSIsContainer } | Select-Object -First 1)) {
Write-Output " $Description"
Write-Output " [OK] $Description"
return $true
} else {
Write-Output " $Description"
Write-Output " [FAIL] $Description"
return $false
}
}
@@ -591,7 +591,7 @@ except Exception:
if ($layerPaths.Count -eq 0) { return $null }
# If the top (highest-priority) layer is replace, it wins entirely
# If the top (highest-priority) layer is replace, it wins entirely --
# lower layers are irrelevant regardless of their strategies.
if ($layerStrategies[0] -eq 'replace') {
return (Get-Content $layerPaths[0] -Raw)
+1 -1
View File
@@ -312,7 +312,7 @@ if (-not $DryRun) {
if ($AllowExistingBranch) {
# If we're already on the branch, continue without another checkout.
if ($currentBranch -eq $branchName) {
# Already on the target branch nothing to do
# Already on the target branch -- nothing to do
} else {
# Otherwise switch to the existing branch instead of failing.
$switchBranchError = git checkout -q $branchName 2>&1 | Out-String
+4 -3
View File
@@ -335,10 +335,11 @@ class TestInitIntegrationFlag:
_install_shared_infra(project, "sh", force=False)
captured = capsys.readouterr()
assert "already exist and were not updated" in captured.out
assert "specify init --here --force" in captured.out
plain = strip_ansi(captured.out)
assert "already exist and were not updated" in plain
assert "specify init --here --force" in plain
# Rich may wrap long lines; normalize whitespace for the second command
normalized = " ".join(captured.out.split())
normalized = " ".join(plain.split())
assert "specify integration upgrade --force" in normalized
def test_shared_infra_warns_when_manifest_cannot_be_loaded(self, tmp_path, capsys):
@@ -7,6 +7,7 @@ import pytest
from typer.testing import CliRunner
from specify_cli import app
from tests.conftest import strip_ansi
runner = CliRunner()
@@ -49,7 +50,8 @@ def _write_invalid_manifest(project, key):
def _integration_list_row_cells(output: str, key: str) -> list[str]:
row = next(line for line in output.splitlines() if line.startswith(f"{key}"))
plain = strip_ansi(output)
row = next(line for line in plain.splitlines() if line.startswith(f"{key}"))
return [cell.strip() for cell in row.split("")[1:-1]]
@@ -160,8 +162,9 @@ class TestIntegrationInstall:
finally:
os.chdir(old_cwd)
assert result.exit_code == 0
assert "already installed" in result.output
normalized = " ".join(result.output.split())
plain = strip_ansi(result.output)
assert "already installed" in plain
normalized = " ".join(plain.split())
assert "specify integration upgrade copilot" in normalized
assert "already the default integration" in normalized
assert "No files were changed" in normalized
@@ -197,9 +200,10 @@ class TestIntegrationInstall:
finally:
os.chdir(old_cwd)
assert result.exit_code != 0
assert "Installed integrations: copilot" in result.output
assert "Default integration: copilot" in result.output
normalized = " ".join(result.output.split())
plain = strip_ansi(result.output)
assert "Installed integrations: copilot" in plain
assert "Default integration: copilot" in plain
normalized = " ".join(plain.split())
assert "To replace the default integration" in normalized
assert "specify integration switch claude" in normalized
assert "To install 'claude' alongside" in normalized
@@ -309,9 +313,10 @@ class TestIntegrationInstall:
finally:
os.chdir(old_cwd)
assert result.exit_code != 0
assert "Installed integrations: copilot" in result.output
assert "multi-install safe" in result.output
normalized = " ".join(result.output.split())
plain = strip_ansi(result.output)
assert "Installed integrations: copilot" in plain
assert "multi-install safe" in plain
normalized = " ".join(plain.split())
assert "To replace the default integration" in normalized
assert "specify integration switch claude" in normalized
assert "To install 'claude' alongside" in normalized
+54
View File
@@ -0,0 +1,54 @@
"""Regression tests for PowerShell 5.1 compatibility (GitHub issue #2680).
PowerShell 5.1 (built-in on Windows) defaults to the system's legacy encoding
when reading .ps1 files. Non-ASCII characters in UTF-8-encoded scripts cause
parse errors because multi-byte sequences are misinterpreted as individual bytes.
These tests ensure that all shipped .ps1 files remain ASCII-only so they work
on both PowerShell 5.1 and 7+.
"""
from pathlib import Path
import pytest
REPO_ROOT = Path(__file__).resolve().parent.parent
# All directories that contain shipped PowerShell scripts.
_PS1_DIRS = [
REPO_ROOT / "scripts" / "powershell",
REPO_ROOT / "extensions" / "git" / "scripts" / "powershell",
]
def _collect_ps1_files():
"""Yield all .ps1 files under the known script directories."""
for d in _PS1_DIRS:
if d.is_dir():
yield from sorted(d.rglob("*.ps1"))
_PS1_FILES = list(_collect_ps1_files())
@pytest.mark.parametrize("ps1_file", _PS1_FILES, ids=lambda p: str(p.relative_to(REPO_ROOT)))
def test_ps1_file_is_ascii_only(ps1_file: Path):
"""Every .ps1 file must contain only ASCII characters (PS 5.1 compat)."""
content = ps1_file.read_bytes()
non_ascii = [
(i, byte)
for i, byte in enumerate(content)
if byte > 127
]
assert not non_ascii, (
f"{ps1_file.relative_to(REPO_ROOT)} contains non-ASCII bytes "
f"(PowerShell 5.1 incompatible): "
f"first at byte offset {non_ascii[0][0]} (0x{non_ascii[0][1]:02x})"
)
def test_ps1_files_discovered():
"""Sanity check: at least the known script files are found."""
names = {p.name for p in _PS1_FILES}
assert "common.ps1" in names
assert "initialize-repo.ps1" in names