Skip to content

Commit a69710e

Browse files
authored
Merge pull request #34 from hyle/misc-fixing
harden export filtering and release versioning
2 parents b96a16b + 3af9ab6 commit a69710e

4 files changed

Lines changed: 97 additions & 24 deletions

File tree

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
- uses: actions/checkout@v5
2727

2828
- name: Build
29-
run: make
29+
run: make VERSION="${GITHUB_REF_NAME}"
3030

3131
- name: Package
3232
run: tar -czf "${{ matrix.asset }}" fuori README.md LICENSE

src/collect.c

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -207,20 +207,9 @@ static int ends_with_ignore_case(const char* text, const char* suffix) {
207207
return equals_ignore_case(text + text_len - suffix_len, suffix);
208208
}
209209

210-
static int is_sensitive_basename_match(const char* basename,
211-
const char* prefix,
212-
int allow_dot_suffix) {
213-
size_t prefix_len;
214-
210+
static int is_sensitive_basename_prefix(const char* basename, const char* prefix) {
215211
if (!basename || !prefix) return 0;
216-
if (!starts_with_ignore_case(basename, prefix)) {
217-
return 0;
218-
}
219-
prefix_len = strlen(prefix);
220-
if (basename[prefix_len] == '\0') {
221-
return 1;
222-
}
223-
return allow_dot_suffix && basename[prefix_len] == '.';
212+
return starts_with_ignore_case(basename, prefix);
224213
}
225214

226215
static int is_sensitive_filename(const char* filepath) {
@@ -234,16 +223,15 @@ static int is_sensitive_filename(const char* filepath) {
234223
basename = slash + 1;
235224
}
236225

237-
if (equals_ignore_case(basename, ".env") ||
238-
starts_with_ignore_case(basename, ".env.") ||
239-
is_sensitive_basename_match(basename, "credential", 1) ||
240-
is_sensitive_basename_match(basename, "credentials", 1) ||
241-
is_sensitive_basename_match(basename, "secret", 1) ||
242-
is_sensitive_basename_match(basename, "secrets", 1) ||
243-
is_sensitive_basename_match(basename, "id_rsa", 1) ||
244-
is_sensitive_basename_match(basename, "id_dsa", 1) ||
245-
is_sensitive_basename_match(basename, "id_ecdsa", 1) ||
246-
is_sensitive_basename_match(basename, "id_ed25519", 1) ||
226+
if (is_sensitive_basename_prefix(basename, ".env") ||
227+
is_sensitive_basename_prefix(basename, "credential") ||
228+
is_sensitive_basename_prefix(basename, "credentials") ||
229+
is_sensitive_basename_prefix(basename, "secret") ||
230+
is_sensitive_basename_prefix(basename, "secrets") ||
231+
is_sensitive_basename_prefix(basename, "id_rsa") ||
232+
is_sensitive_basename_prefix(basename, "id_dsa") ||
233+
is_sensitive_basename_prefix(basename, "id_ecdsa") ||
234+
is_sensitive_basename_prefix(basename, "id_ed25519") ||
247235
ends_with_ignore_case(basename, ".pem") ||
248236
ends_with_ignore_case(basename, ".key")) {
249237
return 1;
@@ -775,6 +763,11 @@ static int collect_recursive_paths(const char* base_path,
775763

776764
dir = opendir(base_path);
777765
if (!dir) {
766+
if (strcmp(base_path, ".") != 0 &&
767+
(errno == EACCES || errno == EPERM)) {
768+
fprintf(stderr, "Warning: Failed to process directory %s\n", base_path);
769+
return 0;
770+
}
778771
perror("Error opening directory");
779772
return -1;
780773
}

src/tree.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,39 @@ static int tree_add_path(TreeNode* root, const char* display_path) {
188188
}
189189

190190
TreeNode* current = root;
191+
if (display_path[0] == '/') {
192+
TreeNode* absolute_root = NULL;
193+
194+
for (size_t i = 0; i < current->child_count; i++) {
195+
if (strcmp(current->children[i]->name, "/") == 0) {
196+
absolute_root = current->children[i];
197+
break;
198+
}
199+
}
200+
201+
if (!absolute_root) {
202+
if (current->child_count == current->child_capacity) {
203+
size_t new_capacity = (current->child_capacity == 0) ? 8 : current->child_capacity * 2;
204+
TreeNode** new_children = realloc(current->children, new_capacity * sizeof(*new_children));
205+
if (!new_children) {
206+
free(path_copy);
207+
return -1;
208+
}
209+
current->children = new_children;
210+
current->child_capacity = new_capacity;
211+
}
212+
213+
absolute_root = tree_node_create("/", 1);
214+
if (!absolute_root) {
215+
free(path_copy);
216+
return -1;
217+
}
218+
current->children[current->child_count++] = absolute_root;
219+
}
220+
221+
current = absolute_root;
222+
}
223+
191224
char* saveptr = NULL;
192225
char* token = strtok_r(path_copy, "/", &saveptr);
193226
while (token) {

tests/test_cli.sh

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,37 @@ EOF_SENSITIVE_NAME_MAIN
142142
cat >"$SENSITIVE_NAME_DIR/credentials.txt" <<'EOF_SENSITIVE_NAME_SECRET'
143143
plain text but sensitive by filename
144144
EOF_SENSITIVE_NAME_SECRET
145+
cat >"$SENSITIVE_NAME_DIR/.envrc" <<'EOF_SENSITIVE_NAME_ENVRC'
146+
export TOKEN=1
147+
EOF_SENSITIVE_NAME_ENVRC
148+
cat >"$SENSITIVE_NAME_DIR/credentials-prod.txt" <<'EOF_SENSITIVE_NAME_CREDENTIALS_DASH'
149+
prod credentials
150+
EOF_SENSITIVE_NAME_CREDENTIALS_DASH
151+
cat >"$SENSITIVE_NAME_DIR/secret_backup" <<'EOF_SENSITIVE_NAME_SECRET_BACKUP'
152+
backup secret
153+
EOF_SENSITIVE_NAME_SECRET_BACKUP
154+
cat >"$SENSITIVE_NAME_DIR/id_rsa_backup" <<'EOF_SENSITIVE_NAME_ID_RSA_BACKUP'
155+
backup ssh key
156+
EOF_SENSITIVE_NAME_ID_RSA_BACKUP
145157
(cd "$SENSITIVE_NAME_DIR" && "$BIN" --no-git -o - >sensitive_name_stdout.txt 2>"$TMPDIR/sensitive_name_stderr.txt")
146158
assert_contains "$SENSITIVE_NAME_DIR/sensitive_name_stdout.txt" "## main.c"
147159
assert_not_contains "$SENSITIVE_NAME_DIR/sensitive_name_stdout.txt" "credentials.txt"
160+
assert_not_contains "$SENSITIVE_NAME_DIR/sensitive_name_stdout.txt" ".envrc"
161+
assert_not_contains "$SENSITIVE_NAME_DIR/sensitive_name_stdout.txt" "credentials-prod.txt"
162+
assert_not_contains "$SENSITIVE_NAME_DIR/sensitive_name_stdout.txt" "secret_backup"
163+
assert_not_contains "$SENSITIVE_NAME_DIR/sensitive_name_stdout.txt" "id_rsa_backup"
148164
assert_contains "$TMPDIR/sensitive_name_stderr.txt" "Warning: Skipping sensitive file ./credentials.txt"
165+
assert_contains "$TMPDIR/sensitive_name_stderr.txt" "Warning: Skipping sensitive file ./.envrc"
166+
assert_contains "$TMPDIR/sensitive_name_stderr.txt" "Warning: Skipping sensitive file ./credentials-prod.txt"
167+
assert_contains "$TMPDIR/sensitive_name_stderr.txt" "Warning: Skipping sensitive file ./secret_backup"
168+
assert_contains "$TMPDIR/sensitive_name_stderr.txt" "Warning: Skipping sensitive file ./id_rsa_backup"
149169

150170
(cd "$SENSITIVE_NAME_DIR" && "$BIN" --no-git --allow-sensitive -o - >sensitive_name_allow_stdout.txt 2>"$TMPDIR/sensitive_name_allow_stderr.txt")
151171
assert_contains "$SENSITIVE_NAME_DIR/sensitive_name_allow_stdout.txt" "## credentials.txt"
172+
assert_contains "$SENSITIVE_NAME_DIR/sensitive_name_allow_stdout.txt" "## .envrc"
173+
assert_contains "$SENSITIVE_NAME_DIR/sensitive_name_allow_stdout.txt" "## credentials-prod.txt"
174+
assert_contains "$SENSITIVE_NAME_DIR/sensitive_name_allow_stdout.txt" "## secret_backup"
175+
assert_contains "$SENSITIVE_NAME_DIR/sensitive_name_allow_stdout.txt" "## id_rsa_backup"
152176
assert_not_contains "$TMPDIR/sensitive_name_allow_stderr.txt" "Warning: Skipping sensitive file"
153177

154178
SENSITIVE_CONTENT_DIR="$TMPDIR/sensitive_content"
@@ -254,6 +278,23 @@ if [ "$(id -u)" -ne 0 ]; then
254278
assert_contains "$PERM_DIR/permission_stderr.txt" "Warning: Failed to process file ./private.txt"
255279
fi
256280

281+
UNREADABLE_DIR="$TMPDIR/unreadable_directory"
282+
mkdir -p "$UNREADABLE_DIR/blocked"
283+
cat >"$UNREADABLE_DIR/main.c" <<'EOF_UNREADABLE_DIR_MAIN'
284+
int main(void) { return 0; }
285+
EOF_UNREADABLE_DIR_MAIN
286+
cat >"$UNREADABLE_DIR/blocked/hidden.c" <<'EOF_UNREADABLE_DIR_HIDDEN'
287+
int hidden(void) { return 0; }
288+
EOF_UNREADABLE_DIR_HIDDEN
289+
if [ "$(id -u)" -ne 0 ]; then
290+
chmod 000 "$UNREADABLE_DIR/blocked"
291+
(cd "$UNREADABLE_DIR" && "$BIN" --no-git --no-tree -o - >unreadable_dir_stdout.txt 2>unreadable_dir_stderr.txt)
292+
chmod 700 "$UNREADABLE_DIR/blocked"
293+
assert_contains "$UNREADABLE_DIR/unreadable_dir_stdout.txt" "## main.c"
294+
assert_not_contains "$UNREADABLE_DIR/unreadable_dir_stdout.txt" "hidden.c"
295+
assert_contains "$UNREADABLE_DIR/unreadable_dir_stderr.txt" "Warning: Failed to process directory ./blocked"
296+
fi
297+
257298
ODD_DIR="$TMPDIR/odd_paths"
258299
mkdir -p "$ODD_DIR"
259300
cat >"$ODD_DIR/main.c" <<'EOF_ODD_MAIN'
@@ -403,6 +444,12 @@ assert_contains "$STDIN_DIR/stdin_spaces_newline_stdout.txt" "## file with space
403444
printf 'file with spaces.txt\0' | (cd "$STDIN_DIR" && "$BIN" --from-stdin --null --no-tree -o - >stdin_spaces_null_stdout.txt 2>stdin_spaces_null_stderr.txt)
404445
assert_contains "$STDIN_DIR/stdin_spaces_null_stdout.txt" "## file with spaces.txt"
405446

447+
ABS_STDIN_PATH=$(cd "$STDIN_DIR" && pwd)/alpha.c
448+
printf '%s\n' "$ABS_STDIN_PATH" | (cd "$STDIN_DIR" && "$BIN" --from-stdin -o - >stdin_absolute_stdout.txt 2>stdin_absolute_stderr.txt)
449+
assert_contains "$STDIN_DIR/stdin_absolute_stdout.txt" "## $ABS_STDIN_PATH"
450+
assert_contains "$STDIN_DIR/stdin_absolute_stdout.txt" "└── /"
451+
assert_contains "$STDIN_DIR/stdin_absolute_stdout.txt" "└── alpha.c"
452+
406453
printf 'beta.c\nalpha.c\n' | (cd "$STDIN_DIR" && "$BIN" --from-stdin --no-tree -o - >stdin_order_stdout.txt 2>stdin_order_stderr.txt)
407454
first_heading=$(grep '^## ' "$STDIN_DIR/stdin_order_stdout.txt" | head -n 1)
408455
if [ "$first_heading" != "## alpha.c" ]; then

0 commit comments

Comments
 (0)