Get current git HEAD hash. buf must be >= CBM_SZ_64. Returns false on error. */
| 226 | |
| 227 | /* Get current git HEAD hash. buf must be >= CBM_SZ_64. Returns false on error. */ |
| 228 | static bool git_head_hash(const char *repo_path, char *buf, size_t bufsz) { |
| 229 | char cmd[CBM_SZ_1K]; |
| 230 | if (!cbm_artifact_repo_path_is_shell_safe(repo_path)) { |
| 231 | buf[0] = '\0'; |
| 232 | return false; |
| 233 | } |
| 234 | int n = |
| 235 | snprintf(cmd, sizeof(cmd), "git -C \"%s\" rev-parse HEAD 2>" ARTIFACT_NULL_DEV, repo_path); |
| 236 | if (n < 0 || (size_t)n >= sizeof(cmd)) { |
| 237 | buf[0] = '\0'; /* truncated command → don't run a malformed shell string (parity with |
| 238 | git_context.c) */ |
| 239 | return false; |
| 240 | } |
| 241 | FILE *fp = cbm_popen(cmd, "r"); |
| 242 | if (!fp) { |
| 243 | buf[0] = '\0'; |
| 244 | return false; |
| 245 | } |
| 246 | buf[0] = '\0'; |
| 247 | if (fgets(buf, (int)bufsz, fp)) { |
| 248 | /* Strip trailing newline */ |
| 249 | size_t len = strlen(buf); |
| 250 | while (len > 0 && (buf[len - ART_NUL] == '\n' || buf[len - ART_NUL] == '\r')) { |
| 251 | buf[--len] = '\0'; |
| 252 | } |
| 253 | } |
| 254 | (void)cbm_pclose(fp); |
| 255 | return buf[0] != '\0'; |
| 256 | } |
| 257 | |
| 258 | /* Generate ISO 8601 timestamp into buf. */ |
| 259 | static void iso_timestamp(char *buf, size_t bufsz) { |
no test coverage detected