mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
The Windows release signed only the three executables Studio builds. The installed tree also ships Electron's ffmpeg.dll, dxcompiler.dll, vk_swiftshader.dll and vulkan-1.dll unsigned, and Smart App Control / WDAC can refuse to load an unsigned low-reputation DLL, so the app may not start. Every PE file the Windows bundle may hold is now declared in scripts/windows-signing-lib.ps1: seven the release signs, and d3dcompiler_47.dll and dxil.dll, which Electron ships signed by Microsoft and which are kept that way and verified as Microsoft-signed. A bundle with an undeclared or missing PE file (.exe, .dll, .node, or any MZ header) fails until a person updates the list. windows-sign-payload signs the declared files, verifies all nine, and records a SHA-256 digest of the whole signed tree as a job output. The signed tree is the payload artifact; windows-package packages it as it came. A new job, windows-verify-package, with no secrets and no environment, checks the payload against that digest, unpacks the zip and the installer's app-64.7z, requires both trees to equal the payload file for file (plus resources/elevate.exe, pinned by SHA-256), and outputs the SHA-256 of both packages. windows-sign-installer only requires the packages to hash to those values before signing, and afterwards only runs SignTool verification, so no archive is parsed in a job holding the Certum credentials and Certum never signs an installer whose contents did not match. Signatures are read from the file itself through SignTool and the embedded signer certificate. Get-AuthenticodeSignature answers from the OS catalog for d3dcompiler_47.dll and reports a catalog signature whatever the file carries. The contract pins the new scripts, and validate now refuses a fingerprint file that runs a script under scripts/ which is not pinned.
428 lines
13 KiB
Go
428 lines
13 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"slices"
|
|
"strings"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
const (
|
|
contractPath = ".signpath/contracts/release-signing.yml"
|
|
projectSlug = "DeepSeek-Reasonix"
|
|
policySlug = "release-signing"
|
|
repository = "https://github.com/esengine/DeepSeek-Reasonix.git"
|
|
)
|
|
|
|
// The studio line has its own tag namespace and its own protected branch, so
|
|
// the origin a signing request must carry is this one and not the desktop
|
|
// line's. Pinned here rather than read from the contract: this guard exists to
|
|
// catch the contract being widened, and a guard that reads its own answer out
|
|
// of the file it is checking cannot.
|
|
var expectedBranches = []string{"studio"}
|
|
|
|
type releaseSigningContract struct {
|
|
Version int `yaml:"version"`
|
|
ProjectSlug string `yaml:"project_slug"`
|
|
SigningPolicySlug string `yaml:"signing_policy_slug"`
|
|
RepositoryURL string `yaml:"repository_url"`
|
|
AllowedBranchNames []string `yaml:"allowed_branch_names"`
|
|
AllowedBuildDefinitions []string `yaml:"allowed_build_definitions"`
|
|
FingerprintFiles []string `yaml:"fingerprint_files"`
|
|
}
|
|
|
|
type workflowInfo struct {
|
|
externallyTriggered bool
|
|
directSigning bool
|
|
calls []string
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) < 2 || len(os.Args) > 3 {
|
|
fatalf("usage: signpath-contract <validate|fingerprint> [repository-root]")
|
|
}
|
|
root := "."
|
|
if len(os.Args) == 3 {
|
|
root = os.Args[2]
|
|
}
|
|
contract, err := loadAndValidate(root)
|
|
if err != nil {
|
|
fatalf("%v", err)
|
|
}
|
|
|
|
switch os.Args[1] {
|
|
case "validate":
|
|
fmt.Println("SignPath release signing contract is valid")
|
|
case "fingerprint":
|
|
fingerprint, err := contractFingerprint(root, contract)
|
|
if err != nil {
|
|
fatalf("fingerprint contract: %v", err)
|
|
}
|
|
fmt.Printf("v1:%x\n", fingerprint)
|
|
default:
|
|
fatalf("unknown command %q", os.Args[1])
|
|
}
|
|
}
|
|
|
|
func fatalf(format string, args ...any) {
|
|
fmt.Fprintf(os.Stderr, "signpath-contract: "+format+"\n", args...)
|
|
os.Exit(1)
|
|
}
|
|
|
|
func loadAndValidate(root string) (releaseSigningContract, error) {
|
|
data, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(contractPath)))
|
|
if err != nil {
|
|
return releaseSigningContract{}, fmt.Errorf("read %s: %w", contractPath, err)
|
|
}
|
|
var contract releaseSigningContract
|
|
if err := yaml.Unmarshal(data, &contract); err != nil {
|
|
return releaseSigningContract{}, fmt.Errorf("parse %s: %w", contractPath, err)
|
|
}
|
|
if err := validateContract(root, contract); err != nil {
|
|
return releaseSigningContract{}, err
|
|
}
|
|
return contract, nil
|
|
}
|
|
|
|
func validateContract(root string, contract releaseSigningContract) error {
|
|
if contract.Version != 1 {
|
|
return fmt.Errorf("%s version is %d, want 1", contractPath, contract.Version)
|
|
}
|
|
if contract.ProjectSlug != projectSlug {
|
|
return fmt.Errorf("project_slug is %q, want %q", contract.ProjectSlug, projectSlug)
|
|
}
|
|
if contract.SigningPolicySlug != policySlug {
|
|
return fmt.Errorf("signing_policy_slug is %q, want %q", contract.SigningPolicySlug, policySlug)
|
|
}
|
|
if contract.RepositoryURL != repository {
|
|
return fmt.Errorf("repository_url is %q, want %q", contract.RepositoryURL, repository)
|
|
}
|
|
if err := requireExactSet("allowed_branch_names", contract.AllowedBranchNames, expectedBranches); err != nil {
|
|
return err
|
|
}
|
|
if len(contract.AllowedBuildDefinitions) == 0 {
|
|
return errors.New("allowed_build_definitions must not be empty")
|
|
}
|
|
for _, value := range append(append([]string{}, contract.AllowedBranchNames...), contract.AllowedBuildDefinitions...) {
|
|
if strings.ContainsAny(value, "*?[") {
|
|
return fmt.Errorf("SignPath allowlists must not contain wildcard %q", value)
|
|
}
|
|
}
|
|
for _, name := range contract.AllowedBuildDefinitions {
|
|
if err := validateRepositoryPath(name); err != nil {
|
|
return fmt.Errorf("invalid allowed build definition %q: %w", name, err)
|
|
}
|
|
if !strings.HasPrefix(name, ".github/workflows/") {
|
|
return fmt.Errorf("allowed build definition %q is outside .github/workflows", name)
|
|
}
|
|
}
|
|
if err := requireUnique("allowed_build_definitions", contract.AllowedBuildDefinitions); err != nil {
|
|
return err
|
|
}
|
|
if len(contract.FingerprintFiles) == 0 {
|
|
return errors.New("fingerprint_files must not be empty")
|
|
}
|
|
seen := make(map[string]bool, len(contract.FingerprintFiles))
|
|
for _, name := range contract.FingerprintFiles {
|
|
if err := validateRepositoryPath(name); err != nil {
|
|
return fmt.Errorf("invalid fingerprint file %q: %w", name, err)
|
|
}
|
|
if seen[name] {
|
|
return fmt.Errorf("duplicate fingerprint file %q", name)
|
|
}
|
|
seen[name] = true
|
|
info, err := os.Stat(filepath.Join(root, filepath.FromSlash(name)))
|
|
if err != nil {
|
|
return fmt.Errorf("fingerprint file %q: %w", name, err)
|
|
}
|
|
if !info.Mode().IsRegular() {
|
|
return fmt.Errorf("fingerprint file %q is not a regular file", name)
|
|
}
|
|
}
|
|
|
|
if err := requireScriptClosure(root, contract.FingerprintFiles); err != nil {
|
|
return err
|
|
}
|
|
|
|
reachable, err := discoverTopLevelSigningWorkflows(root)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := requireExactSet("top-level workflows that reach SignPath", reachable, contract.AllowedBuildDefinitions); err != nil {
|
|
return fmt.Errorf("SignPath build-definition drift: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var scriptReference = regexp.MustCompile(`[A-Za-z0-9_.-]+\.ps1\b`)
|
|
|
|
// A pinned file that runs a script under scripts/ pins nothing unless that
|
|
// script is pinned too, so every one a fingerprint file names must be listed.
|
|
func requireScriptClosure(root string, fingerprintFiles []string) error {
|
|
pinned := make(map[string]bool, len(fingerprintFiles))
|
|
for _, name := range fingerprintFiles {
|
|
pinned[name] = true
|
|
}
|
|
for _, name := range fingerprintFiles {
|
|
data, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(name)))
|
|
if err != nil {
|
|
return fmt.Errorf("read fingerprint file %q: %w", name, err)
|
|
}
|
|
for _, leaf := range scriptReference.FindAllString(string(data), -1) {
|
|
script := "scripts/" + leaf
|
|
info, err := os.Stat(filepath.Join(root, filepath.FromSlash(script)))
|
|
if err != nil || !info.Mode().IsRegular() {
|
|
continue
|
|
}
|
|
if !pinned[script] {
|
|
return fmt.Errorf("fingerprint file %q runs %q, which fingerprint_files does not list", name, script)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func requireExactSet(name string, got, want []string) error {
|
|
gotCopy := append([]string(nil), got...)
|
|
wantCopy := append([]string(nil), want...)
|
|
slices.Sort(gotCopy)
|
|
slices.Sort(wantCopy)
|
|
if len(gotCopy) != len(wantCopy) {
|
|
return fmt.Errorf("%s is %v, want %v", name, got, want)
|
|
}
|
|
for i := range gotCopy {
|
|
if gotCopy[i] != wantCopy[i] {
|
|
return fmt.Errorf("%s is %v, want %v", name, got, want)
|
|
}
|
|
if i > 0 && gotCopy[i] == gotCopy[i-1] {
|
|
return fmt.Errorf("%s contains duplicate %q", name, gotCopy[i])
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func requireUnique(name string, values []string) error {
|
|
seen := make(map[string]bool, len(values))
|
|
for _, value := range values {
|
|
if seen[value] {
|
|
return fmt.Errorf("%s contains duplicate %q", name, value)
|
|
}
|
|
seen[value] = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateRepositoryPath(name string) error {
|
|
if name == "" || filepath.IsAbs(filepath.FromSlash(name)) {
|
|
return errors.New("path must be non-empty and repository-relative")
|
|
}
|
|
clean := filepath.Clean(filepath.FromSlash(name))
|
|
if clean == "." || clean == ".." || strings.HasPrefix(clean, ".."+string(filepath.Separator)) {
|
|
return errors.New("path escapes the repository")
|
|
}
|
|
if filepath.ToSlash(clean) != name {
|
|
return errors.New("path must be normalized with forward slashes")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func discoverTopLevelSigningWorkflows(root string) ([]string, error) {
|
|
paths, err := filepath.Glob(filepath.Join(root, ".github", "workflows", "*.y*ml"))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list workflows: %w", err)
|
|
}
|
|
workflows := make(map[string]workflowInfo, len(paths))
|
|
for _, path := range paths {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read workflow %s: %w", path, err)
|
|
}
|
|
name, err := filepath.Rel(root, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
name = filepath.ToSlash(name)
|
|
info, err := parseWorkflow(data)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parse workflow %s: %w", name, err)
|
|
}
|
|
workflows[name] = info
|
|
}
|
|
|
|
state := make(map[string]uint8, len(workflows))
|
|
memo := make(map[string]bool, len(workflows))
|
|
var reachesSigning func(string) (bool, error)
|
|
reachesSigning = func(name string) (bool, error) {
|
|
if state[name] == 2 {
|
|
return memo[name], nil
|
|
}
|
|
if state[name] == 1 {
|
|
return false, fmt.Errorf("reusable workflow cycle includes %s", name)
|
|
}
|
|
info, ok := workflows[name]
|
|
if !ok {
|
|
return false, fmt.Errorf("workflow calls missing local workflow %s", name)
|
|
}
|
|
state[name] = 1
|
|
reachable := info.directSigning
|
|
for _, called := range info.calls {
|
|
calledReachable, err := reachesSigning(called)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
reachable = reachable || calledReachable
|
|
}
|
|
state[name] = 2
|
|
memo[name] = reachable
|
|
return reachable, nil
|
|
}
|
|
|
|
var result []string
|
|
for name, info := range workflows {
|
|
if !info.externallyTriggered {
|
|
continue
|
|
}
|
|
reachable, err := reachesSigning(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if reachable {
|
|
result = append(result, name)
|
|
}
|
|
}
|
|
slices.Sort(result)
|
|
return result, nil
|
|
}
|
|
|
|
func parseWorkflow(data []byte) (workflowInfo, error) {
|
|
var document yaml.Node
|
|
if err := yaml.Unmarshal(data, &document); err != nil {
|
|
return workflowInfo{}, err
|
|
}
|
|
if len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode {
|
|
return workflowInfo{}, errors.New("workflow root must be a mapping")
|
|
}
|
|
root := document.Content[0]
|
|
on := mappingValue(root, "on")
|
|
jobs := mappingValue(root, "jobs")
|
|
if on == nil || jobs == nil || jobs.Kind != yaml.MappingNode {
|
|
return workflowInfo{}, errors.New("workflow must contain on and jobs mappings")
|
|
}
|
|
|
|
info := workflowInfo{externallyTriggered: hasExternalTrigger(on)}
|
|
for i := 1; i < len(jobs.Content); i += 2 {
|
|
job := jobs.Content[i]
|
|
if job.Kind != yaml.MappingNode {
|
|
continue
|
|
}
|
|
if uses := mappingScalar(job, "uses"); strings.HasPrefix(uses, "./.github/workflows/") {
|
|
info.calls = append(info.calls, strings.TrimPrefix(uses, "./"))
|
|
}
|
|
if nodeContains(job, "secrets.SIGNPATH_API_TOKEN") || nodeContains(job, "secrets.CERTUM_OTP_URI") {
|
|
info.directSigning = true
|
|
}
|
|
steps := mappingValue(job, "steps")
|
|
if steps == nil || steps.Kind != yaml.SequenceNode {
|
|
continue
|
|
}
|
|
for _, step := range steps.Content {
|
|
if step.Kind != yaml.MappingNode {
|
|
continue
|
|
}
|
|
if strings.HasPrefix(mappingScalar(step, "uses"), "signpath/github-action-submit-signing-request@") {
|
|
info.directSigning = true
|
|
}
|
|
}
|
|
}
|
|
slices.Sort(info.calls)
|
|
return info, nil
|
|
}
|
|
|
|
func nodeContains(node *yaml.Node, text string) bool {
|
|
if node == nil {
|
|
return false
|
|
}
|
|
if node.Kind == yaml.ScalarNode && strings.Contains(node.Value, text) {
|
|
return true
|
|
}
|
|
for _, child := range node.Content {
|
|
if nodeContains(child, text) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func hasExternalTrigger(node *yaml.Node) bool {
|
|
switch node.Kind {
|
|
case yaml.ScalarNode:
|
|
return node.Value != "workflow_call"
|
|
case yaml.SequenceNode:
|
|
for _, child := range node.Content {
|
|
if child.Value != "workflow_call" {
|
|
return true
|
|
}
|
|
}
|
|
case yaml.MappingNode:
|
|
for i := 0; i < len(node.Content); i += 2 {
|
|
if node.Content[i].Value != "workflow_call" {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func mappingValue(node *yaml.Node, key string) *yaml.Node {
|
|
if node == nil || node.Kind != yaml.MappingNode {
|
|
return nil
|
|
}
|
|
for i := 0; i < len(node.Content); i += 2 {
|
|
if node.Content[i].Value == key {
|
|
return node.Content[i+1]
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func mappingScalar(node *yaml.Node, key string) string {
|
|
value := mappingValue(node, key)
|
|
if value == nil || value.Kind != yaml.ScalarNode {
|
|
return ""
|
|
}
|
|
return value.Value
|
|
}
|
|
|
|
func contractFingerprint(root string, contract releaseSigningContract) ([sha256.Size]byte, error) {
|
|
names := append([]string{contractPath}, contract.FingerprintFiles...)
|
|
slices.Sort(names)
|
|
hash := sha256.New()
|
|
_, _ = io.WriteString(hash, "reasonix-signpath-release-contract-v1\x00")
|
|
for _, name := range names {
|
|
data, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(name)))
|
|
if err != nil {
|
|
return [sha256.Size]byte{}, fmt.Errorf("read %s: %w", name, err)
|
|
}
|
|
writeLengthPrefixed(hash, []byte(name))
|
|
writeLengthPrefixed(hash, data)
|
|
}
|
|
var result [sha256.Size]byte
|
|
copy(result[:], hash.Sum(nil))
|
|
return result, nil
|
|
}
|
|
|
|
func writeLengthPrefixed(writer io.Writer, data []byte) {
|
|
var length [8]byte
|
|
binary.BigEndian.PutUint64(length[:], uint64(len(data)))
|
|
_, _ = writer.Write(length[:])
|
|
_, _ = writer.Write(data)
|
|
}
|