Merge pull request #27 from bnema/fix/pass-token-list-parsing
fix: improve pass token list parsing robustness
1 file · +18 -3
M internal/adapters/out/tokenstore/pass.go +18 -3
| @@ -6,6 +6,7 @@ import ( | |||
| 6 | 6 | "encoding/json" | |
| 7 | 7 | "fmt" | |
| 8 | 8 | "os/exec" | |
| 9 | + | "regexp" | |
| 9 | 10 | "strings" | |
| 10 | 11 | "time" | |
| 11 | 12 | ||
| @@ -14,6 +15,9 @@ import ( | |||
| 14 | 15 | "gordon/internal/domain" | |
| 15 | 16 | ) | |
| 16 | 17 | ||
| 18 | + | // ansiRegex matches ANSI escape sequences for stripping from pass output. | |
| 19 | + | var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*m`) | |
| 20 | + | ||
| 17 | 21 | const ( | |
| 18 | 22 | // passTokenPath is the base path for tokens in pass. | |
| 19 | 23 | passTokenPath = "gordon/registry/tokens" | |
| @@ -139,13 +143,24 @@ func (s *PassStore) ListTokens(ctx context.Context) ([]domain.Token, error) { | |||
| 139 | 143 | ||
| 140 | 144 | for _, line := range lines { | |
| 141 | 145 | line = strings.TrimSpace(line) | |
| 142 | - | // Skip tree formatting characters and empty lines | |
| 146 | + | ||
| 147 | + | // Strip ANSI escape sequences (pass outputs colored text on TTY) | |
| 148 | + | line = ansiRegex.ReplaceAllString(line, "") | |
| 149 | + | ||
| 150 | + | // Skip tree formatting characters (both Unicode and ASCII variants) | |
| 151 | + | // Unicode: ├── └── │ | |
| 143 | 152 | line = strings.TrimPrefix(line, "├── ") | |
| 144 | 153 | line = strings.TrimPrefix(line, "└── ") | |
| 145 | 154 | line = strings.TrimPrefix(line, "│ ") | |
| 155 | + | // ASCII: |-- `-- | | |
| 156 | + | line = strings.TrimPrefix(line, "|-- ") | |
| 157 | + | line = strings.TrimPrefix(line, "`-- ") | |
| 158 | + | line = strings.TrimPrefix(line, "| ") | |
| 159 | + | ||
| 160 | + | line = strings.TrimSpace(line) | |
| 146 | 161 | ||
| 147 | - | // Skip .meta files and empty lines | |
| 148 | - | if line == "" || strings.HasSuffix(line, ".meta") { | |
| 162 | + | // Skip .meta files, empty lines, and the header line | |
| 163 | + | if line == "" || strings.HasSuffix(line, ".meta") || line == passTokenPath { | |
| 149 | 164 | continue | |
| 150 | 165 | } | |
| 151 | 166 | ||
| @@ -6,6 +6,7 @@ import ( | |||||
| 6 | "encoding/json" | 6 | "encoding/json" | ||
| 7 | "fmt" | 7 | "fmt" | ||
| 8 | "os/exec" | 8 | "os/exec" | ||
| 9 | + | "regexp" | |||
| 9 | "strings" | 10 | "strings" | ||
| 10 | "time" | 11 | "time" | ||
| 11 | 12 | ||||
| @@ -14,6 +15,9 @@ import ( | |||||
| 14 | "gordon/internal/domain" | 15 | "gordon/internal/domain" | ||
| 15 | ) | 16 | ) | ||
| 16 | 17 | ||||
| 18 | + | // ansiRegex matches ANSI escape sequences for stripping from pass output. | |||
| 19 | + | var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*m`) | |||
| 20 | + | ||||
| 17 | const ( | 21 | const ( | ||
| 18 | // passTokenPath is the base path for tokens in pass. | 22 | // passTokenPath is the base path for tokens in pass. | ||
| 19 | passTokenPath = "gordon/registry/tokens" | 23 | passTokenPath = "gordon/registry/tokens" | ||
| @@ -139,13 +143,24 @@ func (s *PassStore) ListTokens(ctx context.Context) ([]domain.Token, error) { | |||||
| 139 | 143 | ||||
| 140 | for _, line := range lines { | 144 | for _, line := range lines { | ||
| 141 | line = strings.TrimSpace(line) | 145 | line = strings.TrimSpace(line) | ||
| 142 | - | // Skip tree formatting characters and empty lines | 146 | + | |
| 147 | + | // Strip ANSI escape sequences (pass outputs colored text on TTY) | |||
| 148 | + | line = ansiRegex.ReplaceAllString(line, "") | |||
| 149 | + | ||||
| 150 | + | // Skip tree formatting characters (both Unicode and ASCII variants) | |||
| 151 | + | // Unicode: ├── └── │ | |||
| 143 | line = strings.TrimPrefix(line, "├── ") | 152 | line = strings.TrimPrefix(line, "├── ") | ||
| 144 | line = strings.TrimPrefix(line, "└── ") | 153 | line = strings.TrimPrefix(line, "└── ") | ||
| 145 | line = strings.TrimPrefix(line, "│ ") | 154 | line = strings.TrimPrefix(line, "│ ") | ||
| 155 | + | // ASCII: |-- `-- | | |||
| 156 | + | line = strings.TrimPrefix(line, "|-- ") | |||
| 157 | + | line = strings.TrimPrefix(line, "`-- ") | |||
| 158 | + | line = strings.TrimPrefix(line, "| ") | |||
| 159 | + | ||||
| 160 | + | line = strings.TrimSpace(line) | |||
| 146 | 161 | ||||
| 147 | - | // Skip .meta files and empty lines | 162 | + | // Skip .meta files, empty lines, and the header line |
| 148 | - | if line == "" || strings.HasSuffix(line, ".meta") { | 163 | + | if line == "" || strings.HasSuffix(line, ".meta") || line == passTokenPath { |
| 149 | continue | 164 | continue | ||
| 150 | } | 165 | } | ||
| 151 | 166 | ||||