-
Notifications
You must be signed in to change notification settings - Fork 5
test: overhaul tests #339
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
base: master
Are you sure you want to change the base?
test: overhaul tests #339
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,4 +2,6 @@ | |
| graphify-out/ | ||
|
|
||
| # Added by ggshield | ||
| .cache_ggshield | ||
| .cache_ggshield | ||
|
|
||
| coverage.out | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Ignore the coverage file produced by CI. The workflow writes 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -162,16 +162,16 @@ func decode(variant Variant, parts []string) (digest algorithm.Digest, err error | |
| return nil, fmt.Errorf("%w: key has 0 bytes", algorithm.ErrEncodedHashKeyEncoding) | ||
| } | ||
|
|
||
| if decoded.t == 0 { | ||
| decoded.t = 1 | ||
| if decoded.t < IterationsMin { | ||
| return nil, fmt.Errorf(algorithm.ErrFmtInvalidIntParameter, algorithm.ErrEncodedHashInvalidOptionValue, oT, IterationsMin, "", uint32(IterationsMax), decoded.t) | ||
| } | ||
|
|
||
| if decoded.p == 0 { | ||
| decoded.p = 4 | ||
| if decoded.p < ParallelismMin || decoded.p > ParallelismMax { | ||
| return nil, fmt.Errorf(algorithm.ErrFmtInvalidIntParameter, algorithm.ErrEncodedHashInvalidOptionValue, oP, ParallelismMin, "", uint32(ParallelismMax), decoded.p) | ||
| } | ||
|
|
||
| if decoded.m == 0 { | ||
| decoded.m = 32 * 1024 | ||
| if decoded.m < MemoryMin { | ||
| return nil, fmt.Errorf(algorithm.ErrFmtInvalidIntParameter, algorithm.ErrEncodedHashInvalidOptionValue, oM, MemoryMin, "", MemoryMax, decoded.m) | ||
|
Comment on lines
+173
to
+174
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Map the Argon2 package before inspecting the relevant declarations.
ast-grep outline algorithm/argon2 --items all
# Inspect parameter bounds and all local uses of decoded memory and parallelism.
rg -n -C 4 'MemoryMin|MemoryMax|MemoryMinParallelismMultiplier|ParallelismMin|ParallelismMax' algorithm/argon2
rg -n -C 4 'argon2\.(IDKey|Key)|func \(.*Digest.*\) Match|func .*Validate' algorithm/argon2
rg -n -C 3 'golang.org/x/crypto' go.mod go.sumRepository: go-crypt/crypt Length of output: 11667 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- decoder.go ---'
sed -n '1,210p' algorithm/argon2/decoder.go
printf '%s\n' '--- regression_test.go ---'
sed -n '1,220p' algorithm/argon2/regression_test.go
printf '%s\n' '--- dependency declarations ---'
rg -n -C 3 'go-crypt/x/argon2|golang.org/x/crypto/argon2' go.mod go.sum
printf '%s\n' '--- tracked dependency source ---'
git ls-files | rg '(^|/)(vendor/.*argon2|argon2/.*\.go)$' || trueRepository: go-crypt/crypt Length of output: 7866 🌐 Web query:
💡 Result: The library github.com/go-crypt/x implements feature parity with golang.org/x/crypto for its cryptographic functions [1][2]. Consequently, its Argon2 implementation follows the same functional requirements and constraints as the standard golang.org/x/crypto/argon2 package [3][4]. In Go's reference Argon2 implementations (including the code base utilized by go-crypt/x), the core requirements for memory and parallelism are enforced as follows: 1. Parallelism (threads): The parallelism degree must be greater than zero [5][3]. Code implementations typically panic if the value is less than 1 [3]. 2. Memory: The memory cost must be sufficient to provide at least 8 KiB per thread [3]. Internally, if the requested memory is too low, the implementation adjusts or mandates a minimum; specifically, it requires that memory be at least 8 * threads (in KiB) [3]. While some higher-level wrappers or libraries (such as various crypt packages) define explicit constants like ParallelismMin = 1 or MemoryMin = 8 * Parallelism, these are library-specific constraints rather than hard-coded limits in the underlying algorithm implementation, which fundamentally relies on the parameters remaining positive [3][6][7]. The Argon2 standard and Go implementations generally expect memory to be provided in KiB, and it is recommended to use at least 32 MiB to 64 MiB for production security [5][3]. Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- module files and dependency references ---'
git ls-files | rg '(^|/)(go\.mod|go\.sum|go\.work)$' | xargs -r -n1 sh -c 'echo "--- $0"; sed -n "1,180p" "$0"'
rg -n -C 4 'github.com/go-crypt/x|golang.org/x/crypto' . --glob '!*.sum' --glob '!*.mod' || true
printf '%s\n' '--- dependency source references in repository history metadata ---'
rg -n 'go-crypt/x/argon2|github.com/go-crypt/x' .git 2>/dev/null | head -80 || trueRepository: go-crypt/crypt Length of output: 9688 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
import json
import urllib.request
urls = [
"https://api.github.com/repos/go-crypt/x/contents/argon2/argon2.go",
"https://api.github.com/repos/go-crypt/x/contents/argon2",
]
for url in urls:
print(f"--- {url} ---")
req = urllib.request.Request(url, headers={"Accept": "application/vnd.github+json", "User-Agent": "review-check"})
with urllib.request.urlopen(req, timeout=20) as response:
data = json.load(response)
if isinstance(data, dict) and "content" in data:
import base64
print(base64.b64decode(data["content"]).decode())
else:
for item in data:
print(item.get("name"), item.get("type"), item.get("sha"))
PYRepository: go-crypt/crypt Length of output: 2513 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- cached module locations ---'
if command -v go >/dev/null 2>&1; then
gomodcache="$(go env GOMODCACHE)"
printf 'GOMODCACHE=%s\n' "$gomodcache"
find "$gomodcache/github.com/go-crypt" -maxdepth 4 -type f \( -path '*x@v0.4.16/argon2/*.go' -o -path '*x@v0.4.16/go.mod' \) -print 2>/dev/null || true
fi
printf '%s\n' '--- pinned dependency source ---'
for file in argon2/argon2.go argon2/blake2b.go argon2/argon2_test.go; do
url="https://raw.githubusercontent.com/go-crypt/x/v0.4.16/$file"
echo "--- $url ---"
curl -k -fsSL "$url" | sed -n '1,260p' || true
doneRepository: go-crypt/crypt Length of output: 19685 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- digest call path ---'
sed -n '1,150p' algorithm/argon2/digest.go
sed -n '145,190p' algorithm/argon2/hasher.go
sed -n '1,100p' algorithm/argon2/const.go
printf '%s\n' '--- dependency normalization constants and logic ---'
curl -k -fsSL https://raw.githubusercontent.com/go-crypt/x/v0.4.16/argon2/argon2.go |
rg -n -C 8 'syncPoints|memory = memory|memory < 2|deriveKey'
printf '%s\n' '--- RFC references in repository ---'
rg -n -C 3 'RFC.?9106|8.?\\*.?p|memory.*parallel|minimum.*memory|MemoryMinParallelismMultiplier' algorithm/argon2 README.md doc.goRepository: go-crypt/crypt Length of output: 21558 🌐 Web query:
💡 Result: According to RFC 9106, the memory size parameter (m) MUST be an integer number of kibibytes from 8p to 2^(32)-1, where p is the degree of parallelism (number of lanes) [1][2]. This requirement (m >= 8p) ensures that each of the p lanes has enough memory to be partitioned into the required number of segments [1]. Argon2 partitions the memory matrix into SL = 4 slices per lane [1]. Since each lane is divided into these slices and the computation involves specific synchronization points, the minimum memory size is mathematically tied to the parallelism to prevent undersized allocations that would break the algorithm's internal structure [1][3]. If the requested memory m is less than 8p, the implementation will violate the specification [1][2]. In practice, compliant implementations—such as those reflected in library documentation—enforce this constraint by requiring the user to provide a valid m >= 8p [4][5][6]. Some implementations may include internal logic to automatically round up or adjust the memory blocks if an invalid configuration is provided, often setting the minimum to 8p or a multiple of 4p to maintain the necessary segment structure [3][7]. Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
MEMORY_MIN_PARALLELISM_MULTIPLIER = 8
MEMORY_ROUNDING_PARALLELISM_MULTIPLIER = 4
SYNC_POINTS = 4
parallelism_max = 16_777_215
def effective_memory(memory, parallelism):
rounded = (memory // (SYNC_POINTS * parallelism)) * (SYNC_POINTS * parallelism)
return max(rounded, 2 * SYNC_POINTS * parallelism)
for memory, parallelism in [(8, 1), (8, 2), (15, 2), (16, 2), (2**32 - 1, parallelism_max)]:
required = memory if parallelism == 1 else parallelism * MEMORY_MIN_PARALLELISM_MULTIPLIER
print({
"m": memory,
"p": parallelism,
"required_m": parallelism * MEMORY_MIN_PARALLELISM_MULTIPLIER,
"decoder_accepts_currently": memory >= 8,
"spec_parameter_valid": memory >= parallelism * MEMORY_MIN_PARALLELISM_MULTIPLIER,
"dependency_effective_memory": effective_memory(memory, parallelism),
"uint32_product": (parallelism * MEMORY_MIN_PARALLELISM_MULTIPLIER) & 0xffffffff,
"wide_product": parallelism * MEMORY_MIN_PARALLELISM_MULTIPLIER,
})
PYRepository: go-crypt/crypt Length of output: 1082 Reject memory below the selected parallelism minimum. The decoder accepts invalid parameters such as 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| return decoded, nil | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| package argon2 | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestDecodeRejectsParametersItCannotHonour(t *testing.T) { | ||
| testCases := []struct { | ||
| name string | ||
| digest string | ||
| }{ | ||
| {"ZeroIterations", "$argon2id$v=19$m=8,t=0,p=1$c2FsdHNhbHQ$a2V5a2V5a2V5a2V5"}, | ||
| {"ZeroParallelism", "$argon2id$v=19$m=8,t=1,p=0$c2FsdHNhbHQ$a2V5a2V5a2V5a2V5"}, | ||
| {"ZeroMemory", "$argon2id$v=19$m=0,t=1,p=1$c2FsdHNhbHQ$a2V5a2V5a2V5a2V5"}, | ||
| {"MemoryBelowMinimum", "$argon2id$v=19$m=1,t=1,p=1$c2FsdHNhbHQ$a2V5a2V5a2V5a2V5"}, | ||
| {"ParallelismAboveMaximum", "$argon2id$v=19$m=8,t=1,p=16777216$c2FsdHNhbHQ$a2V5a2V5a2V5a2V5"}, | ||
| } | ||
|
|
||
| for _, tc := range testCases { | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| digest, err := Decode(tc.digest) | ||
|
|
||
| assert.Nil(t, digest) | ||
| assert.Error(t, err) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestDecodePreservesParameters(t *testing.T) { | ||
| testCases := []string{ | ||
| "$argon2id$v=19$m=8,t=1,p=1$c2FsdHNhbHQ$a2V5a2V5a2V5a2V5", | ||
| "$argon2i$v=19$m=65536,t=3,p=4$c2FsdHNhbHQ$a2V5a2V5a2V5a2V5", | ||
| "$argon2d$v=19$m=2097152,t=1,p=4$c2FsdHNhbHQ$a2V5a2V5a2V5a2V5", | ||
| } | ||
|
|
||
| for _, encoded := range testCases { | ||
| t.Run(encoded, func(t *testing.T) { | ||
| digest, err := Decode(encoded) | ||
|
|
||
| require.NoError(t, err) | ||
| assert.Equal(t, encoded, digest.Encode()) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestHashedDigestsRoundTrip(t *testing.T) { | ||
| for _, variant := range []Variant{VariantID, VariantI, VariantD} { | ||
| t.Run(variant.String(), func(t *testing.T) { | ||
| hasher, err := New(WithVariant(variant), WithProfileRFC9106LowMemory()) | ||
| require.NoError(t, err) | ||
| require.NoError(t, hasher.Validate()) | ||
|
|
||
| digest, err := hasher.Hash("password") | ||
| require.NoError(t, err) | ||
|
|
||
| encoded := digest.Encode() | ||
|
|
||
| decoded, err := Decode(encoded) | ||
| require.NoError(t, err, "encoded digest %q could not be decoded", encoded) | ||
|
|
||
| assert.Equal(t, encoded, decoded.Encode()) | ||
| assert.True(t, decoded.Match("password")) | ||
| assert.False(t, decoded.Match("incorrect")) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestDecodeVariantRejectsOtherVariants(t *testing.T) { | ||
| const encoded = "$argon2i$v=19$m=8,t=1,p=1$c2FsdHNhbHQ$a2V5a2V5a2V5a2V5" | ||
|
|
||
| digest, err := DecodeVariant(VariantID)(encoded) | ||
|
|
||
| assert.Nil(t, digest) | ||
| assert.Error(t, err) | ||
|
|
||
| digest, err = DecodeVariant(VariantI)(encoded) | ||
|
|
||
| require.NoError(t, err) | ||
| assert.Equal(t, encoded, digest.Encode()) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| package bcrypt | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| xbcrypt "github.com/go-crypt/x/bcrypt" | ||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestDecodeRejectsUnusableCost(t *testing.T) { | ||
| testCases := []struct { | ||
| name string | ||
| digest string | ||
| }{ | ||
| {"StandardNegative", "$2b$-1$" + validStandardKey}, | ||
| {"StandardZero", "$2b$00$" + validStandardKey}, | ||
| {"StandardBelowMinimum", "$2b$03$" + validStandardKey}, | ||
| {"StandardAboveMaximum", "$2b$99$" + validStandardKey}, | ||
| {"SHA256Zero", "$bcrypt-sha256$v=2,t=2b,r=0$" + validSHA256Salt + "$" + validSHA256Key}, | ||
| {"SHA256AboveMaximum", "$bcrypt-sha256$v=2,t=2b,r=99$" + validSHA256Salt + "$" + validSHA256Key}, | ||
| } | ||
|
|
||
| for _, tc := range testCases { | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| digest, err := Decode(tc.digest) | ||
|
|
||
| assert.Nil(t, digest) | ||
| assert.Error(t, err) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestDecodeAcceptsLegacyCosts(t *testing.T) { | ||
| for _, cost := range []string{"04", "05", "09", "31"} { | ||
| t.Run(cost, func(t *testing.T) { | ||
| encoded := "$2b$" + cost + "$" + validStandardKey | ||
|
|
||
| digest, err := Decode(encoded) | ||
|
|
||
| require.NoError(t, err) | ||
| assert.Equal(t, encoded, digest.Encode()) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestDecodeAcceptsEveryCostTheKeyDerivationAccepts(t *testing.T) { | ||
| assert.NoError(t, validateCost(xbcrypt.MinCost)) | ||
| assert.NoError(t, validateCost(xbcrypt.MaxCost)) | ||
| assert.Error(t, validateCost(xbcrypt.MinCost-1)) | ||
| assert.Error(t, validateCost(xbcrypt.MaxCost+1)) | ||
| } | ||
|
|
||
| func TestHashedDigestsRoundTrip(t *testing.T) { | ||
| testCases := []struct { | ||
| name string | ||
| new func() (*Hasher, error) | ||
| }{ | ||
| {"Standard", func() (*Hasher, error) { return New(WithCost(IterationsMin)) }}, | ||
| {"SHA256", func() (*Hasher, error) { return NewSHA256(WithCost(IterationsMin)) }}, | ||
| } | ||
|
|
||
| for _, tc := range testCases { | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| hasher, err := tc.new() | ||
| require.NoError(t, err) | ||
| require.NoError(t, hasher.Validate()) | ||
|
|
||
| digest, err := hasher.Hash("password") | ||
| require.NoError(t, err) | ||
|
|
||
| encoded := digest.Encode() | ||
|
|
||
| decoded, err := Decode(encoded) | ||
| require.NoError(t, err, "encoded digest %q could not be decoded", encoded) | ||
|
|
||
| assert.Equal(t, encoded, decoded.Encode()) | ||
| assert.True(t, decoded.Match("password")) | ||
| assert.False(t, decoded.Match("incorrect")) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestSHA256VariantIsNotLimitedTo72Bytes(t *testing.T) { | ||
| long := make([]byte, 200) | ||
|
|
||
| for i := range long { | ||
| long[i] = byte('a' + i%26) | ||
| } | ||
|
|
||
| hasher, err := NewSHA256(WithCost(IterationsMin)) | ||
| require.NoError(t, err) | ||
|
|
||
| digest, err := hasher.Hash(string(long)) | ||
| require.NoError(t, err) | ||
|
|
||
| assert.True(t, digest.MatchBytes(long)) | ||
|
|
||
| truncated := append(append([]byte{}, long[:72]...), []byte("different")...) | ||
|
|
||
| assert.False(t, digest.MatchBytes(truncated)) | ||
| } | ||
|
|
||
| const ( | ||
| validStandardKey = "3XCpXfcQBjcbXFHTLcbFju0KNQ2ipfeNbcH8b7ZgIkXlbNkYbGDWm" | ||
| validSHA256Salt = "3XCpXfcQBjcbXFHTLcbFju" | ||
| validSHA256Key = "AXNZ1B7NPTf7XyCqUKcvIUOB5eKKZ4C" | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,7 @@ const ( | |
| EncodingFmtSun = "$md5$%s$$%s" | ||
|
|
||
| // EncodingFmtSunIterations is the encoding format for this algorithm when using md5crypt.VariantSun and iterations more than 0. | ||
| EncodingFmtSunIterations = "$md5,iterations=%d$%s$$%s" | ||
| EncodingFmtSunIterations = "$md5,rounds=%d$%s$$%s" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
ast-grep outline algorithm/md5crypt --items all --type function,method
rg -n -C 5 'WithIterations|IterationsMin|IterationsMax|EncodingFmtSunIterations|ParameterRounds|ParameterIterations' algorithm/md5cryptRepository: go-crypt/crypt Length of output: 10832 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- md5crypt constants/options/digest/decoder ---'
sed -n '1,90p' algorithm/md5crypt/const.go
sed -n '1,120p' algorithm/md5crypt/opts.go
sed -n '1,125p' algorithm/md5crypt/digest.go
sed -n '100,175p' algorithm/md5crypt/decoder.go
printf '%s\n' '--- related validation and decoder tests ---'
rg -n -C 4 'IterationsMin|IterationsMax|IterationsDefault|ParameterRounds|ParameterIterations|rounds=|iterations=' algorithm
rg -n -C 3 'RegisterDecoderSun|DecodeVariant|ErrEncodedHashInvalidOptionValue|invalid.*iteration|invalid.*round' algorithm/md5crypt algorithmRepository: go-crypt/crypt Length of output: 50370 🌐 Web query:
💡 Result: In the context of the SunMD5 password hashing algorithm implemented in libxcrypt, the processing cost parameter (the number of rounds) has a specified range of 4096 to 4,294,963,199 [1][2][3]. The SunMD5 algorithm, originally developed for Solaris, defines the number of rounds as an additional cost factor [4]. The libxcrypt documentation for crypt(5) explicitly states that the processing cost parameter for SunMD5 falls within the range of 4096 to 4,294,963,199 [1][2][5]. This minimum value of 4096 reflects the default number of rounds, which is often considered the baseline, and values cannot effectively be lowered below this threshold [4]. The upper limit of 4,294,963,199 is consistent with the maximum value allowed by the underlying implementation's design [6][7]. Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- md5crypt decoder flow ---'
sed -n '45,115p' algorithm/md5crypt/decoder.go
sed -n '1,90p' algorithm/md5crypt/hasher.go
sed -n '1,90p' algorithm/md5crypt/regression_test.go
sed -n '1,90p' algorithm/md5crypt/md5crypt_test.go
printf '%s\n' '--- exact SunMD5 specification text ---'
curl -L --fail --silent --show-error \
https://raw.githubusercontent.com/besser82/libxcrypt/develop/doc/crypt.5 |
rg -n -C 8 'SunMD5|4096|4294963199'Repository: go-crypt/crypt Length of output: 10434 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
const = Path("algorithm/md5crypt/const.go").read_text()
digest = Path("algorithm/md5crypt/digest.go").read_text()
decoder = Path("algorithm/md5crypt/decoder.go").read_text()
min_value = int(re.search(r"IterationsMin\s*=\s*(\d+)", const).group(1))
max_value = int(re.search(r"IterationsMax\s+uint32\s*=\s*math\.MaxUint32", const) and 2**32 - 1)
assert "d.variant == VariantSun && d.iterations > 0" in digest
assert "case ParameterRounds, ParameterIterations:" in decoder
assert "decoded.iterations = uint32(value)" in decoder
canonical_min = 4096
canonical_max = 4_294_963_199
for value in (1000, canonical_min, canonical_max, max_value):
emits_parameter = value > 0
canonical = canonical_min <= value <= canonical_max
print(f"{value}: emits rounds={emits_parameter}, canonical={canonical}")
assert min_value == 0
assert max_value == 4_294_967_295
assert 0 < 1000 < canonical_min
assert canonical_max < max_value
PYRepository: go-crypt/crypt Length of output: 326 Restrict Sun MD5
📍 Affects 3 files
🤖 Prompt for AI Agents |
||
|
|
||
| // AlgName is the name for this algorithm. | ||
| AlgName = "md5crypt" | ||
|
|
@@ -23,6 +23,13 @@ const ( | |
| // AlgIdentifierVariantSun is the identifier used in this algorithm when using md5crypt.VariantSun. | ||
| AlgIdentifierVariantSun = "md5" | ||
|
|
||
| // ParameterRounds is the parameter name used by the Sun variant of this algorithm to carry the iteration count. | ||
| ParameterRounds = "rounds" | ||
|
|
||
| // ParameterIterations is a non standard parameter name for the iteration count which earlier versions of this | ||
| // library emitted. It is accepted when decoding so those digests remain readable. | ||
| ParameterIterations = "iterations" | ||
|
|
||
| // VariantNameStandard is the md5crypt.Variant name for md5crypt.VariantStandard. | ||
| VariantNameStandard = "standard" | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: go-crypt/crypt
Length of output: 5426
🏁 Script executed:
Repository: go-crypt/crypt
Length of output: 308
🌐 Web query:
actions/checkout persist-credentials default stores token in local git config documentation GitHub pull_request fork GITHUB_TOKEN read-only💡 Result:
The
actions/checkoutaction uses thepersist-credentialsinput to control how it handles authentication for Git commands within your workflow [1][2]. 1. Default Behavior ofpersist-credentials: By default,persist-credentialsis set totrue[2][3]. When enabled,actions/checkoutconfigures the local Git environment to use the provided token or SSH key, allowing subsequent Git commands (likegit fetchorgit push) to run authenticated [1][4]. 2. Token Storage: Historically, this token was stored directly in the local.git/configfile [1][4]. However, recent versions ofactions/checkouthave improved security by storing these credentials in a separate file under$RUNNER_TEMPinstead of modifying.git/configdirectly [4][5]. The credentials are removed during the post-job cleanup process [1][3]. You can disable this persistence entirely by settingpersist-credentials: falsein your workflow step [1][4]. 3.GITHUB_TOKENand Fork Pull Requests: When a workflow is triggered by apull_requestevent from a fork, GitHub restricts theGITHUB_TOKENto read-only permissions [6][7]. This is a security measure to prevent untrusted code in a pull request from accessing secrets or modifying the repository [6]. Because of this restriction, even ifactions/checkoutpersists aGITHUB_TOKENin a fork-basedpull_requestworkflow, that token will generally lack the write permissions necessary to push changes back to the repository [7]. If you require write access for automation (e.g., automated merging or status updates) on pull requests from forks, it is common to use thepull_request_targetevent instead [6][7], though this requires careful security practices because it grants the workflow access to the base repository's secrets and read/writeGITHUB_TOKEN[6].Citations:
Disable persisted checkout credentials for the fuzz job.
The job runs pull-request code with a read-only
GITHUB_TOKEN. Unless authenticated Git is required, setpersist-credentials: falseon itsactions/checkoutstep.🧰 Tools
🪛 zizmor (1.29.0)
[warning] 91-92: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 Prompt for AI Agents
Source: Linters/SAST tools