stringutil

package
v0.68.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 16, 2026 License: MIT Imports: 8 Imported by: 0

README

stringutil Package

The stringutil package provides utility functions for working with strings. It is organized into focused sub-files covering ANSI stripping, identifier normalization, sanitization, URL utilities, and PAT (Personal Access Token) validation.

Overview

Sub-file Functions
stringutil.go General string helpers
ansi.go ANSI escape-code stripping
identifiers.go Workflow name and path normalization
sanitize.go Security-sensitive string sanitization
urls.go URL normalization and domain extraction
pat_validation.go GitHub PAT classification and validation

General Utilities (stringutil.go)

Truncate(s string, maxLen int) string

Truncates s to at most maxLen characters, appending "..." when truncation occurs. For maxLen ≤ 3 the string is truncated without ellipsis.

stringutil.Truncate("hello world", 8) // "hello..."
stringutil.Truncate("hi", 8)          // "hi"
NormalizeWhitespace(content string) string

Collapses multiple consecutive whitespace characters (spaces, tabs, newlines) into a single space and trims leading/trailing whitespace.

ParseVersionValue(version any) string

Converts a any-typed version value (typically from YAML parsing, which may produce int, float64, or string) into a string. Returns an empty string for nil.

stringutil.ParseVersionValue("20")    // "20"
stringutil.ParseVersionValue(20)      // "20"
stringutil.ParseVersionValue(20.0)    // "20"
IsPositiveInteger(s string) bool

Returns true if s is a non-empty string containing only digit characters (0–9).

ANSI Escape Code Stripping (ansi.go)

StripANSI(s string) string

Removes all ANSI/VT100 escape sequences from s. Handles CSI sequences (e.g. \x1b[31m for colors) and other ESC-prefixed sequences. This function is used before writing text into YAML files to prevent invisible characters from corrupting workflow output.

colored := "\x1b[32mSuccess\x1b[0m"
plain := stringutil.StripANSI(colored) // "Success"

Identifier Normalization (identifiers.go)

NormalizeWorkflowName(name string) string

Removes .md and .lock.yml extensions from workflow names, returning the bare workflow identifier.

stringutil.NormalizeWorkflowName("weekly-research.md")       // "weekly-research"
stringutil.NormalizeWorkflowName("weekly-research.lock.yml") // "weekly-research"
stringutil.NormalizeWorkflowName("weekly-research")          // "weekly-research"
NormalizeSafeOutputIdentifier(identifier string) string

Converts dashes to underscores in safe-output identifiers, normalizing the user-facing dash-separated format to the internal underscore_separated format.

stringutil.NormalizeSafeOutputIdentifier("create-issue") // "create_issue"
MarkdownToLockFile(mdPath string) string

Converts a workflow markdown path (.md) to its compiled lock file path (.lock.yml). Returns the path unchanged if it already ends with .lock.yml.

stringutil.MarkdownToLockFile(".github/workflows/test.md")
// → ".github/workflows/test.lock.yml"
LockFileToMarkdown(lockPath string) string

Converts a compiled lock file path (.lock.yml) back to its markdown source path (.md). Returns the path unchanged if it already ends with .md.

stringutil.LockFileToMarkdown(".github/workflows/test.lock.yml")
// → ".github/workflows/test.md"

Sanitization (sanitize.go)

These functions remove sensitive information to prevent accidental leakage in logs or error messages.

SanitizeErrorMessage(message string) string

Redacts potential secret key names from error messages. Matches uppercase SNAKE_CASE identifiers (e.g. MY_SECRET_KEY, API_TOKEN) and PascalCase identifiers ending with security-related suffixes (e.g. GitHubToken, ApiKey). Common GitHub Actions workflow keywords (GITHUB, RUNNER, WORKFLOW, etc.) are excluded from redaction.

stringutil.SanitizeErrorMessage("Error: MY_SECRET_TOKEN is invalid")
// → "Error: [REDACTED] is invalid"
SanitizeParameterName(name string) string

Sanitizes a parameter name for use as a GitHub Actions output or environment variable name. Replaces non-alphanumeric characters with underscores.

SanitizePythonVariableName(name string) string

Sanitizes a string for use as a Python variable name. Similar to SanitizeParameterName but follows Python identifier rules.

SanitizeToolID(toolID string) string

Sanitizes a tool identifier for safe use in generated code. Replaces characters that are not valid in identifiers with underscores.

SanitizeForFilename(slug string) string

Converts a string into a filesystem-safe filename by lowercasing and replacing non-alphanumeric characters with hyphens.

URL Utilities (urls.go)

NormalizeGitHubHostURL(rawHostURL string) string

Normalizes a GitHub host URL by ensuring it has an https:// scheme and no trailing slash. Accepts bare hostnames, URLs with or without a scheme, and URLs with trailing slashes.

stringutil.NormalizeGitHubHostURL("github.example.com")        // "https://github.example.com"
stringutil.NormalizeGitHubHostURL("https://github.com/")       // "https://github.com"
ExtractDomainFromURL(urlStr string) string

Extracts the hostname (without port) from a URL string. Falls back to simple string parsing when url.Parse cannot handle the input.

stringutil.ExtractDomainFromURL("https://api.github.com/repos") // "api.github.com"

PAT Validation (pat_validation.go)

PATType

A string type representing the category of a GitHub Personal Access Token.

Constant Value Prefix
PATTypeFineGrained "fine-grained" github_pat_
PATTypeClassic "classic" ghp_
PATTypeOAuth "oauth" gho_
PATTypeUnknown "unknown" (other)

Methods: String() string, IsFineGrained() bool, IsValid() bool

ClassifyPAT(token string) PATType

Determines the token type from its prefix.

ValidateCopilotPAT(token string) error

Returns nil if the token is a fine-grained PAT; returns an actionable error message with a link to create the correct token type otherwise.

if err := stringutil.ValidateCopilotPAT(token); err != nil {
    fmt.Fprintln(os.Stderr, console.FormatErrorMessage(err.Error()))
}
GetPATTypeDescription(token string) string

Returns a human-readable description of the token type (e.g. "fine-grained personal access token").

Design Notes

  • All debug output uses namespace-prefixed loggers (stringutil:identifiers, stringutil:sanitize, stringutil:urls, stringutil:pat_validation) and is only emitted when DEBUG=stringutil:*.
  • SanitizeErrorMessage is intentionally conservative: it excludes common GitHub Actions keywords to avoid over-redacting legitimate error messages.
  • StripANSI handles both CSI sequences (ESC[) and other ESC-prefixed sequences to cover the full range of ANSI escape codes found in terminal output.

Documentation

Overview

Package stringutil provides utility functions for working with strings.

Package stringutil provides utility functions for working with strings.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExtractDomainFromURL

func ExtractDomainFromURL(urlStr string) string

ExtractDomainFromURL extracts the domain name from a URL string. Handles various URL formats including full URLs with protocols, URLs with ports, and plain domain names.

This function uses net/url.Parse for proper URL parsing when a protocol is present, and falls back to string manipulation for other formats.

Examples:

ExtractDomainFromURL("https://mcp.tavily.com/mcp/")           // returns "mcp.tavily.com"
ExtractDomainFromURL("http://api.example.com:8080/path")      // returns "api.example.com"
ExtractDomainFromURL("mcp.example.com")                       // returns "mcp.example.com"
ExtractDomainFromURL("github.com:443")                        // returns "github.com"
ExtractDomainFromURL("http://sub.domain.com:8080/path")       // returns "sub.domain.com"
ExtractDomainFromURL("localhost:8080")                        // returns "localhost"

func GetPATTypeDescription added in v0.45.1

func GetPATTypeDescription(token string) string

GetPATTypeDescription returns a human-readable description of the PAT type

func IsPositiveInteger

func IsPositiveInteger(s string) bool

IsPositiveInteger checks if a string is a positive integer. Returns true for strings like "1", "123", "999" but false for:

  • Zero ("0")
  • Negative numbers ("-5")
  • Numbers with leading zeros ("007")
  • Floating point numbers ("3.14")
  • Non-numeric strings ("abc")
  • Empty strings ("")

func LockFileToMarkdown

func LockFileToMarkdown(lockPath string) string

LockFileToMarkdown converts a compiled lock file path back to its markdown source path. This is used when navigating from compiled workflows back to source files.

The function removes the .lock.yml extension and adds .md extension. If the input already has a .md extension, it returns the path unchanged.

Examples:

LockFileToMarkdown("weekly-research.lock.yml")              // returns "weekly-research.md"
LockFileToMarkdown(".github/workflows/test.lock.yml")       // returns ".github/workflows/test.md"
LockFileToMarkdown("workflow.md")                           // returns "workflow.md" (unchanged)
LockFileToMarkdown("my.workflow.lock.yml")                  // returns "my.workflow.md"

func MarkdownToLockFile

func MarkdownToLockFile(mdPath string) string

MarkdownToLockFile converts a workflow markdown file path to its compiled lock file path. This is the standard transformation for agentic workflow files.

The function removes the .md extension and adds .lock.yml extension. If the input already has a .lock.yml extension, it returns the path unchanged.

Examples:

MarkdownToLockFile("weekly-research.md")                    // returns "weekly-research.lock.yml"
MarkdownToLockFile(".github/workflows/test.md")             // returns ".github/workflows/test.lock.yml"
MarkdownToLockFile("workflow.lock.yml")                     // returns "workflow.lock.yml" (unchanged)
MarkdownToLockFile("my.workflow.md")                        // returns "my.workflow.lock.yml"

func NormalizeGitHubHostURL added in v0.51.7

func NormalizeGitHubHostURL(rawHostURL string) string

NormalizeGitHubHostURL ensures the host URL has a scheme (defaulting to https://) and no trailing slashes. It is safe to call with URLs that already have an http:// or https:// scheme.

func NormalizeSafeOutputIdentifier

func NormalizeSafeOutputIdentifier(identifier string) string

NormalizeSafeOutputIdentifier converts dashes and periods to underscores for safe output identifiers. This standardizes identifier format to the internal underscore-separated format used in safe outputs configuration and MCP tool names.

Both dash-separated and underscore-separated formats are valid inputs. Periods are also replaced because MCP tool names must match ^[a-zA-Z0-9_-]+$ and periods are not permitted. Workflow names such as "executor-workflow.agent" (where ".agent" is a filename extension convention) would otherwise produce an invalid tool name.

This function performs normalization only - it assumes the input is already a valid identifier and does NOT perform character validation or sanitization.

Examples:

NormalizeSafeOutputIdentifier("create-issue")          // returns "create_issue"
NormalizeSafeOutputIdentifier("create_issue")          // returns "create_issue" (unchanged)
NormalizeSafeOutputIdentifier("add-comment")           // returns "add_comment"
NormalizeSafeOutputIdentifier("update-pr")             // returns "update_pr"
NormalizeSafeOutputIdentifier("executor-workflow.agent") // returns "executor_workflow_agent"

func NormalizeWhitespace

func NormalizeWhitespace(content string) string

NormalizeWhitespace normalizes trailing whitespace and newlines to reduce spurious conflicts. It trims trailing whitespace from each line and ensures exactly one trailing newline.

func NormalizeWorkflowName

func NormalizeWorkflowName(name string) string

NormalizeWorkflowName removes .md and .lock.yml extensions from workflow names. This is used to standardize workflow identifiers regardless of the file format.

The function checks for extensions in order of specificity: 1. Removes .lock.yml extension (the compiled workflow format) 2. Removes .md extension (the markdown source format) 3. Returns the name unchanged if no recognized extension is found

This function performs normalization only - it assumes the input is already a valid identifier and does NOT perform character validation or sanitization.

Examples:

NormalizeWorkflowName("weekly-research")           // returns "weekly-research"
NormalizeWorkflowName("weekly-research.md")        // returns "weekly-research"
NormalizeWorkflowName("weekly-research.lock.yml")  // returns "weekly-research"
NormalizeWorkflowName("my.workflow.md")            // returns "my.workflow"

func ParseVersionValue

func ParseVersionValue(version any) string

ParseVersionValue converts version values of various types to strings. Supports string, int, int64, uint64, and float64 types. Returns empty string for unsupported types.

func SanitizeErrorMessage

func SanitizeErrorMessage(message string) string

SanitizeErrorMessage removes potential secret key names from error messages to prevent information disclosure via logs. This prevents exposing details about an organization's security infrastructure by redacting secret key names that might appear in error messages.

func SanitizeForFilename added in v0.55.0

func SanitizeForFilename(slug string) string

SanitizeForFilename converts a repository slug (owner/repo) to a filename-safe string. Replaces "/" with "-". Returns "clone-mode" if the slug is empty.

Examples:

SanitizeForFilename("owner/repo")  // returns "owner-repo"
SanitizeForFilename("")            // returns "clone-mode"

func SanitizeParameterName

func SanitizeParameterName(name string) string

SanitizeParameterName converts a parameter name to a safe JavaScript identifier by replacing non-alphanumeric characters with underscores.

This function ensures that parameter names from workflows can be used safely in JavaScript code by: 1. Replacing any non-alphanumeric characters (except $ and _) with underscores 2. Prepending an underscore if the name starts with a number

Valid characters: a-z, A-Z, 0-9 (not at start), _, $

Examples:

SanitizeParameterName("my-param")        // returns "my_param"
SanitizeParameterName("my.param")        // returns "my_param"
SanitizeParameterName("123param")        // returns "_123param"
SanitizeParameterName("valid_name")      // returns "valid_name"
SanitizeParameterName("$special")        // returns "$special"

func SanitizePythonVariableName

func SanitizePythonVariableName(name string) string

SanitizePythonVariableName converts a parameter name to a valid Python identifier by replacing non-alphanumeric characters with underscores.

This function ensures that parameter names from workflows can be used safely in Python code by: 1. Replacing any non-alphanumeric characters (except _) with underscores 2. Prepending an underscore if the name starts with a number

Valid characters: a-z, A-Z, 0-9 (not at start), _ Note: Python does not allow $ in identifiers (unlike JavaScript)

Examples:

SanitizePythonVariableName("my-param")        // returns "my_param"
SanitizePythonVariableName("my.param")        // returns "my_param"
SanitizePythonVariableName("123param")        // returns "_123param"
SanitizePythonVariableName("valid_name")      // returns "valid_name"

func SanitizeToolID

func SanitizeToolID(toolID string) string

SanitizeToolID removes common MCP prefixes and suffixes from tool IDs. This cleans up tool identifiers by removing redundant MCP-related naming patterns.

The function: 1. Removes "mcp-" prefix 2. Removes "-mcp" suffix 3. Returns the original ID if the result would be empty

Examples:

SanitizeToolID("notion-mcp")        // returns "notion"
SanitizeToolID("mcp-notion")        // returns "notion"
SanitizeToolID("some-mcp-server")   // returns "some-server"
SanitizeToolID("github")            // returns "github" (unchanged)
SanitizeToolID("mcp")               // returns "mcp" (prevents empty result)

func StripANSI added in v0.47.0

func StripANSI(s string) string

StripANSI removes ANSI escape codes from a string using a comprehensive byte scanner. It handles CSI sequences (\x1b[), OSC sequences (\x1b]), G0/G1 character set selections, keypad mode sequences, reset sequences, and other common 2-character escape sequences.

This is more thorough than regex-based approaches and correctly handles edge cases such as incomplete sequences, nested sequences, and non-standard terminal sequences.

func Truncate

func Truncate(s string, maxLen int) string

Truncate truncates a string to a maximum length, adding "..." if truncated. If maxLen is 3 or less, the string is truncated without "...".

This is a general-purpose utility for truncating any string to a configurable length. For domain-specific workflow command identifiers with newline handling, see workflow.ShortenCommand instead.

func ValidateCopilotPAT added in v0.45.1

func ValidateCopilotPAT(token string) error

ValidateCopilotPAT validates that a token is a valid fine-grained PAT for Copilot. Returns an error if the token is not a fine-grained PAT with a descriptive error message.

Parameters:

  • token: The token string to validate

Returns:

  • error: An error with a descriptive message if the token is not valid, nil otherwise

Types

type PATType added in v0.45.1

type PATType string

PATType represents the type of a GitHub Personal Access Token

const (
	// PATTypeFineGrained is a fine-grained personal access token (starts with "github_pat_")
	PATTypeFineGrained PATType = "fine-grained"
	// PATTypeClassic is a classic personal access token (starts with "ghp_")
	PATTypeClassic PATType = "classic"
	// PATTypeOAuth is an OAuth token (starts with "gho_")
	PATTypeOAuth PATType = "oauth"
	// PATTypeUnknown is an unknown token type
	PATTypeUnknown PATType = "unknown"
)

func ClassifyPAT added in v0.45.1

func ClassifyPAT(token string) PATType

ClassifyPAT determines the type of a GitHub Personal Access Token based on its prefix.

Token prefixes:

  • "github_pat_" = Fine-grained PAT (required for Copilot)
  • "ghp_" = Classic PAT (not supported for Copilot)
  • "gho_" = OAuth token (not a PAT at all)

Parameters:

  • token: The token string to classify

Returns:

  • PATType: The type of the token

func (PATType) IsFineGrained added in v0.45.1

func (p PATType) IsFineGrained() bool

IsFineGrained returns true if the token is a fine-grained PAT

func (PATType) IsValid added in v0.45.1

func (p PATType) IsValid() bool

IsValid returns true if the token type is known (not unknown)

func (PATType) String added in v0.45.1

func (p PATType) String() string

String returns the string representation of a PATType

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL