aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2025-07-02 15:46:51 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2025-07-02 15:46:51 -0400
commit97677a0f53d1881e4e89d660fcc21ff3afac121e (patch)
tree136cf4c83bd71fa90e65d4bf9adae4e526b7b969
parent983074bc6f355f2023b6a1475e9bb252881c5d28 (diff)
downloadstasis-fail-on-baked-in-vcs-requirements.tar.gz
Ban Python packages with VCS requirement URLs in their setup scripts/configsfail-on-baked-in-vcs-requirements
-rw-r--r--src/lib/core/include/utils.h3
-rw-r--r--src/lib/core/utils.c84
-rw-r--r--src/lib/delivery/delivery_build.c12
-rw-r--r--src/lib/delivery/delivery_test.c12
4 files changed, 111 insertions, 0 deletions
diff --git a/src/lib/core/include/utils.h b/src/lib/core/include/utils.h
index 1512285..a9bcd2f 100644
--- a/src/lib/core/include/utils.h
+++ b/src/lib/core/include/utils.h
@@ -461,4 +461,7 @@ int in_ascii_range(char c, char lower, char upper);
#define GIT_HASH_LEN 40
int is_git_sha(char const *hash);
+
+int check_python_package_dependencies(const char *srcdir);
+
#endif //STASIS_UTILS_H
diff --git a/src/lib/core/utils.c b/src/lib/core/utils.c
index 3d9659d..62f3bec 100644
--- a/src/lib/core/utils.c
+++ b/src/lib/core/utils.c
@@ -994,3 +994,87 @@ int is_git_sha(char const *hash) {
return 1;
}
+static int read_vcs_records(const size_t line, char **data) {
+ (void) line; // unused
+ const char *vcs_name[] = {
+ "git",
+ "svn",
+ "hg",
+ "bzr",
+ };
+ for (size_t i = 0; i < sizeof(vcs_name) / sizeof(vcs_name[0]); i++) {
+ const char *vcs = vcs_name[i];
+ char *data_local = strdup(*data);
+ if (!data_local) {
+ fprintf(stderr, "Out of memory\n");
+ return -1;
+ }
+
+ // Remove leading/trailing blanks
+ lstrip(data_local);
+ strip(data_local);
+
+ // Ignore file comment(s)
+ if (startswith(data_local, "#") || startswith(data_local, ";")) {
+ // continue
+ return 1;
+ }
+
+ // Begin matching VCS package syntax
+ const char *match_vcs = strstr(data_local,vcs);
+ if (match_vcs) {
+ const char *match_protocol_sep = strstr(match_vcs, "+");
+ if (match_protocol_sep) {
+ const char *match_protocol = strstr(match_protocol_sep, "://");
+ if (match_protocol) {
+ guard_free(data_local);
+ // match found
+ return 0;
+ }
+ }
+ }
+ guard_free(data_local);
+ }
+
+ // no match, continue
+ return 1;
+}
+int check_python_package_dependencies(const char *srcdir) {
+ const char *configs[] = {
+ "pyproject.toml",
+ "setup.cfg",
+ "setup.py"
+ };
+
+ for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); i++) {
+ char path[PATH_MAX] = {0};
+ const char *configfile = configs[i];
+
+ snprintf(path, sizeof(path), "%s/%s", srcdir, configfile);
+ if (access(path, F_OK) < 0) {
+ continue;
+ }
+
+ //char **data = file_readlines(path, 0, 0, NULL);
+ struct StrList *data = strlist_init();
+ int err = 0;
+ if ((err = strlist_append_file(data, path, read_vcs_records))) {
+ guard_strlist_free(&data);
+ return -1;
+ }
+ const size_t count = strlist_count(data);
+ if (count) {
+ printf("\nERROR: VCS requirement(s) detected in %s:\n", configfile);
+ for (size_t j = 0; j < count; j++) {
+ char *record = strlist_item(data, j);
+ lstrip(record);
+ strip(record);
+ printf("[%zu] %s\n", j, record);
+ }
+ guard_strlist_free(&data);
+ return 1;
+ }
+ guard_strlist_free(&data);
+ }
+ return 0;
+}
diff --git a/src/lib/delivery/delivery_build.c b/src/lib/delivery/delivery_build.c
index 2d891d2..c5093d4 100644
--- a/src/lib/delivery/delivery_build.c
+++ b/src/lib/delivery/delivery_build.c
@@ -173,6 +173,18 @@ struct StrList *delivery_build_wheels(struct Delivery *ctx) {
memset(outdir, 0, sizeof(outdir));
memset(cmd, 0, sizeof(outdir));
+ const int dep_status = check_python_package_dependencies(".");
+ if (dep_status) {
+ fprintf(stderr, "\nPlease replace all occurrences above with standard package specs:\n"
+ "\n"
+ " package==x.y.z\n"
+ " package>=x.y.z\n"
+ " package<=x.y.z\n"
+ " ...\n"
+ "\n");
+ COE_CHECK_ABORT(dep_status, "Unreproducible delivery");
+ }
+
strcpy(dname, ctx->tests[i].name);
tolower_s(dname);
sprintf(outdir, "%s/%s", ctx->storage.wheel_artifact_dir, dname);
diff --git a/src/lib/delivery/delivery_test.c b/src/lib/delivery/delivery_test.c
index e80e0ec..6e0a226 100644
--- a/src/lib/delivery/delivery_test.c
+++ b/src/lib/delivery/delivery_test.c
@@ -97,6 +97,18 @@ void delivery_tests_run(struct Delivery *ctx) {
if (pushd(destdir)) {
COE_CHECK_ABORT(1, "Unable to enter repository directory\n");
} else {
+ int dep_status = check_python_package_dependencies(".");
+ if (dep_status) {
+ fprintf(stderr, "\nPlease replace all occurrences above with standard package specs:\n"
+ "\n"
+ " package==x.y.z\n"
+ " package>=x.y.z\n"
+ " package<=x.y.z\n"
+ " ...\n"
+ "\n");
+ COE_CHECK_ABORT(dep_status, "Unreproducible delivery");
+ }
+
char *cmd = calloc(strlen(test->script) + STASIS_BUFSIZ, sizeof(*cmd));
if (!cmd) {
SYSERROR("Unable to allocate test script buffer: %s", strerror(errno));