mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-09 17:48:52 +00:00
21aeed4f4e
Phase 0 closure (Path B2, post-rewrite):
addlicense sweep — adds the canonical certctl LLC copyright + BUSL-1.1
SPDX header to every production Go file. Template:
// Copyright 2026 certctl LLC. All rights reserved.
// SPDX-License-Identifier: BUSL-1.1
Coverage: 338 / 338 production Go files (cmd/ + internal/, excluding
*_test.go and **/testdata/**). Pre-sweep coverage was 22 / 338 (6.5%);
post-sweep is 338 / 338 (100%).
Normalized 22 pre-existing legacy headers (`// Copyright (c) certctl`
+ `// SPDX-License-Identifier: BSL-1.1`) and 1 file using a
`Certctl Contributors` attribution. The legacy SPDX ID `BSL-1.1`
is non-standard; the official SPDX identifier for Business Source
License 1.1 is `BUSL-1.1` (capital U). All 338 files now share the
canonical form.
Generated via:
addlicense -c "certctl LLC" -y 2026 \
-f cowork/legal/copyright-header.tpl \
-ignore '**/testdata/**' -ignore '**/*_test.go' \
cmd/ internal/
Verification:
find cmd internal -name '*.go' -not -name '*_test.go' \
-not -path '*/testdata/*' \
-exec grep -L '^// Copyright 2026 certctl LLC' {} \; | wc -l
Returns: 0
gofmt clean. Header additions are comments only, no compile impact.
Closes: cowork/certctl-architecture-diligence-audit.html#fix-RED-4
93 lines
2.9 KiB
Go
93 lines
2.9 KiB
Go
// Copyright 2026 certctl LLC. All rights reserved.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package iis
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/masterzen/winrm"
|
|
)
|
|
|
|
// WinRMConfig holds WinRM connection settings for remote IIS management.
|
|
// Used when Mode is "winrm" — the proxy agent connects to a remote Windows
|
|
// server over WinRM and executes PowerShell commands remotely.
|
|
type WinRMConfig struct {
|
|
Host string `json:"winrm_host"` // WinRM target hostname or IP (required)
|
|
Port int `json:"winrm_port"` // WinRM port (default 5985 for HTTP, 5986 for HTTPS)
|
|
Username string `json:"winrm_username"` // Windows user (e.g., "Administrator")
|
|
Password string `json:"winrm_password"` // Windows password
|
|
UseHTTPS bool `json:"winrm_https"` // Use HTTPS (port 5986) instead of HTTP (port 5985)
|
|
Insecure bool `json:"winrm_insecure"` // Skip TLS certificate verification (for self-signed certs)
|
|
Timeout int `json:"winrm_timeout"` // Operation timeout in seconds (default 60)
|
|
}
|
|
|
|
// winrmExecutor implements PowerShellExecutor by running PowerShell commands
|
|
// on a remote Windows server via WinRM. This enables the proxy agent pattern:
|
|
// a Linux agent in the same network zone manages Windows IIS servers remotely.
|
|
type winrmExecutor struct {
|
|
client *winrm.Client
|
|
}
|
|
|
|
// newWinRMExecutor creates a WinRM client and returns a PowerShellExecutor.
|
|
func newWinRMExecutor(cfg *WinRMConfig) (*winrmExecutor, error) {
|
|
if cfg.Host == "" {
|
|
return nil, fmt.Errorf("winrm_host is required for WinRM mode")
|
|
}
|
|
if cfg.Username == "" {
|
|
return nil, fmt.Errorf("winrm_username is required for WinRM mode")
|
|
}
|
|
if cfg.Password == "" {
|
|
return nil, fmt.Errorf("winrm_password is required for WinRM mode")
|
|
}
|
|
|
|
port := cfg.Port
|
|
if port == 0 {
|
|
if cfg.UseHTTPS {
|
|
port = 5986
|
|
} else {
|
|
port = 5985
|
|
}
|
|
}
|
|
|
|
timeout := time.Duration(cfg.Timeout) * time.Second
|
|
if cfg.Timeout == 0 {
|
|
timeout = 60 * time.Second
|
|
}
|
|
|
|
endpoint := winrm.NewEndpoint(
|
|
cfg.Host,
|
|
port,
|
|
cfg.UseHTTPS,
|
|
cfg.Insecure,
|
|
nil, // CA cert
|
|
nil, // Client cert
|
|
nil, // Client key
|
|
timeout,
|
|
)
|
|
|
|
client, err := winrm.NewClient(endpoint, cfg.Username, cfg.Password)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create WinRM client: %w", err)
|
|
}
|
|
|
|
return &winrmExecutor{client: client}, nil
|
|
}
|
|
|
|
// Execute runs a PowerShell script on the remote Windows server via WinRM.
|
|
// The script is wrapped in powershell.exe invocation on the remote side.
|
|
func (e *winrmExecutor) Execute(ctx context.Context, script string) (string, error) {
|
|
// RunPSWithContext returns (stdout, stderr, exitCode, error)
|
|
stdout, stderr, exitCode, err := e.client.RunPSWithContext(ctx, script)
|
|
if err != nil {
|
|
return stdout + stderr, fmt.Errorf("WinRM command failed: %w", err)
|
|
}
|
|
if exitCode != 0 {
|
|
return stdout + stderr, fmt.Errorf("PowerShell exited with code %d: %s", exitCode, stdout+stderr)
|
|
}
|
|
|
|
return stdout, nil
|
|
}
|