IgnoreInlineComment doesn't stop it adding `'s
Version
1.67.0
Describe the bug
I have some code that parses the output of an AWS command. I use:
cfg, err := ini.LoadSources(ini.LoadOptions{
InsensitiveSections: true,
IgnoreInlineComment: true,
SkipUnrecognizableLines: true, // Ignore the initial output pre-sections
}, output)
output is something like:
[profile Environment-Blah.PowerUserAccess]
sso_start_url = https://blah.awsapps.com/start#/
sso_region = us-east-1
sso_account_name = [Environment] Blah
sso_account_id = 111111
sso_role_name = PowerUserAccess
region = us-east-1
credential_process = aws-sso-util credential-process --profile blah
sso_auto_populated = true
Later when setting up certain profiles I do:
profileSection.Key("sso_start_url").SetValue(fmt.Sprintf("https://%s/start#/", envConfig.SSOStart))
When I save the .aws/config file however, I always get:
[profile blah-develop-admin]
sso_start_url = `'https://blah.awsapps.com/start#/'`
It will always wrap the output in because of the # in the url. No matter what I do, """ quoting, single quotes, double quotes, anything, it still wraps that entire value in. It's as if this code from go-ini is ignored:
if strings.ContainsAny(val, "\n`") {
val = `"""` + val + `"""`
} else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") {
val = "`" + val + "`"
I'd appreciate any ideas or help you could suggest, I cannot make this stop wrapping it in `. I did find a related bug, https://github.com/go-ini/ini/issues/282, but it seemed like the solution maybe worked for @5nafu.
To reproduce
.
Expected behavior
No `'s in the output.
Additional context
No response
Code of Conduct
- [X] I agree to follow this project's Code of Conduct
I spent some time trying to make test cases to understand this issue better. This was written with the help of Claude.ai, but I was able to reproduce it with minimal code. Here's a bug report fresh out of the AI:
Backticks incorrectly added around URLs containing '#' when using ini.Empty()
Description
When using ini.Empty() to create a new configuration and setting URLs containing the # character, backticks are incorrectly added around the URL value in the output file. This does not occur when loading and copying existing configurations.
Reproduction Steps
package main
import (
"fmt"
"gopkg.in/ini.v1"
)
func main() {
// Case 1: Using ini.Empty() (produces backticks)
cfg1 := ini.Empty()
section1, _ := cfg1.NewSection("test-section")
section1.Key("sso_start_url").SetValue("https://example.com/start#/")
// Case 2: Loading from source (works correctly)
sourceData := `[test-section]
sso_start_url = https://example.com/start#/`
cfg2, _ := ini.LoadSources(ini.LoadOptions{}, []byte(sourceData))
}
Expected Behavior
The URL should be written to the file without surrounding backticks:
[test-section]
sso_start_url = https://example.com/start#/
Actual Behavior
The URL is written with surrounding backticks:
[test-section]
sso_start_url = `https://example.com/start#/`
Test Cases Results
We've tested various scenarios:
- Loading from source and copying sections (WORKS):
[test-section]
sso_start_url = https://example.com/start#/
- Using ini.Empty() (FAILS):
[test-section]
sso_start_url = `https://example.com/start#/`
- Using NewKey instead of Key().SetValue() (FAILS):
[test-section]
sso_start_url = `https://example.com/start#/`
- Different URL formats:
[test-section]
url1 = `https://example.com/start#/` # With # (fails)
url2 = http://example.com/start # Without # (works)
url3 = https://example.com/start?param=value # With ? (works)
This suggests the issue is specifically related to the '#' character when using ini.Empty().
Environment
- go-ini version: v1.67.0
- Go version: 1.23.2
- OS: Linux
Additional Notes
- The issue appears to be related specifically to the '#' character in URLs
- The problem occurs regardless of whether using
Key().SetValue()orNewKey() - Various escape options (
UnescapeValueCommentSymbols,PreserveSurroundedQuote, etc.) do not prevent the issue - The issue does not occur when loading from source and copying sections, only when creating new sections in an empty config
Impact
This causes issues when generating AWS configuration files, as the backticks make the configuration invalid for AWS tools. The URLs need to be written without backticks to be valid.
Also the tests I ran were:
package main
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"gopkg.in/ini.v1"
)
func printConfig(name string, cfg *ini.File) {
tempFile := filepath.Join(os.TempDir(), fmt.Sprintf("ini-test-%s.tmp", name))
err := cfg.SaveTo(tempFile)
if err != nil {
fmt.Printf("Error saving %s: %v\n", name, err)
return
}
content, err := os.ReadFile(tempFile)
if err != nil {
fmt.Printf("Error reading %s: %v\n", name, err)
return
}
fmt.Printf("\n=== %s ===\n", name)
fmt.Println(string(content))
// Clean up temp file
os.Remove(tempFile)
}
func main() {
// Initial test data
sampleData := `[profile Environment-Blah.PowerUserAccess]
sso_start_url = https://blah.awsapps.com/start#/
sso_region = us-east-1
sso_account_name = [Environment] Blah
sso_account_id = 111111
sso_role_name = PowerUserAccess
region = us-east-1
credential_process = aws-sso-util credential-process --profile blah
sso_auto_populated = true`
// Get this as command output for consistency with original
cmd := exec.Command("echo", sampleData)
var output bytes.Buffer
cmd.Stdout = &output
_ = cmd.Run()
// Test 1: Original approach (load from source and copy)
fmt.Println("\nTest 1: Original approach (load and copy)")
cfg1, _ := ini.LoadSources(ini.LoadOptions{
InsensitiveSections: true,
IgnoreInlineComment: true,
SkipUnrecognizableLines: true,
}, output.Bytes())
oldSection := cfg1.Section("profile Environment-Blah.PowerUserAccess")
newSection, _ := cfg1.NewSection("new-section")
for _, key := range oldSection.Keys() {
newSection.Key(key.Name()).SetValue(key.Value())
}
newSection.Key("sso_start_url").SetValue("https://blah2/start#/")
printConfig("test1", cfg1)
// Test 2: Using ini.Empty()
fmt.Println("\nTest 2: Using ini.Empty()")
cfg2 := ini.Empty()
section2, _ := cfg2.NewSection("test-section")
section2.Key("sso_start_url").SetValue("https://blah2/start#/")
section2.Key("sso_region").SetValue("us-east-1")
printConfig("test2", cfg2)
// Test 3: Using NewKey instead of Key().SetValue()
fmt.Println("\nTest 3: Using NewKey")
cfg3 := ini.Empty()
section3, _ := cfg3.NewSection("test-section")
_, _ = section3.NewKey("sso_start_url", "https://blah2/start#/")
_, _ = section3.NewKey("sso_region", "us-east-1")
printConfig("test3", cfg3)
// Test 4: Using different URL formats
fmt.Println("\nTest 4: Different URL formats")
cfg4 := ini.Empty()
section4, _ := cfg4.NewSection("test-section")
section4.Key("url1").SetValue("https://blah2/start#/")
section4.Key("url2").SetValue("http://blah2/start")
section4.Key("url3").SetValue("https://blah2/start?param=value")
printConfig("test4", cfg4)
// Test 5: Load and modify existing
fmt.Println("\nTest 5: Load and modify existing")
cfg5, _ := ini.LoadSources(ini.LoadOptions{}, []byte(`[section]
sso_start_url = https://original/start#/`))
section5 := cfg5.Section("section")
section5.Key("sso_start_url").SetValue("https://blah2/start#/")
printConfig("test5", cfg5)
// Test 6: Empty with escape disabled
fmt.Println("\nTest 6: Empty with escape disabled")
cfg6 := ini.Empty(ini.LoadOptions{
UnescapeValueCommentSymbols: true,
})
section6, _ := cfg6.NewSection("test-section")
section6.Key("sso_start_url").SetValue("https://blah2/start#/")
printConfig("test6", cfg6)
}