Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IgnoreInlineComment doesn't stop it adding `'s #360

Open
1 task done
apenney opened this issue Nov 5, 2024 · 2 comments
Open
1 task done

IgnoreInlineComment doesn't stop it adding `'s #360

apenney opened this issue Nov 5, 2024 · 2 comments
Labels
bug Something isn't working

Comments

@apenney
Copy link

apenney commented Nov 5, 2024

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, #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

  • I agree to follow this project's Code of Conduct
@apenney apenney added the bug Something isn't working label Nov 5, 2024
@apenney
Copy link
Author

apenney commented Nov 5, 2024

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:

  1. Loading from source and copying sections (WORKS):
[test-section]
sso_start_url = https://example.com/start#/
  1. Using ini.Empty() (FAILS):
[test-section]
sso_start_url = `https://example.com/start#/`
  1. Using NewKey instead of Key().SetValue() (FAILS):
[test-section]
sso_start_url = `https://example.com/start#/`
  1. 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() or NewKey()
  • 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.

@apenney
Copy link
Author

apenney commented Nov 5, 2024

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)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant