qalita 2.5.3__py3-none-any.whl → 2.5.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. qalita/_frontend/node_modules/react/cjs/react-compiler-runtime.production.js +16 -0
  2. qalita/_frontend/node_modules/react/cjs/react-jsx-dev-runtime.production.js +14 -0
  3. qalita/_frontend/node_modules/react/cjs/react-jsx-runtime.production.js +34 -0
  4. qalita/_frontend/node_modules/react/cjs/react.production.js +542 -0
  5. qalita/_frontend/node_modules/react/compiler-runtime.js +14 -0
  6. qalita/_frontend/node_modules/react/index.js +1 -1
  7. qalita/_frontend/node_modules/react/jsx-dev-runtime.js +1 -1
  8. qalita/_frontend/node_modules/react/jsx-runtime.js +1 -1
  9. qalita/_frontend/node_modules/react/package.json +19 -15
  10. qalita/_frontend/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +6603 -0
  11. qalita/_frontend/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +6692 -0
  12. qalita/_frontend/node_modules/react-dom/cjs/react-dom-server.browser.production.js +7410 -0
  13. qalita/_frontend/node_modules/react-dom/cjs/react-dom-server.edge.production.js +7512 -0
  14. qalita/_frontend/node_modules/react-dom/cjs/react-dom-server.node.production.js +7707 -0
  15. qalita/_frontend/node_modules/react-dom/cjs/react-dom.production.js +210 -0
  16. qalita/_frontend/node_modules/react-dom/index.js +1 -1
  17. qalita/_frontend/node_modules/react-dom/package.json +75 -20
  18. qalita/_frontend/node_modules/react-dom/server.browser.js +3 -4
  19. qalita/_frontend/node_modules/react-dom/server.edge.js +17 -0
  20. qalita/_frontend/node_modules/react-dom/server.node.js +5 -4
  21. qalita/_frontend/node_modules/react-dom/static.node.js +14 -0
  22. qalita/_frontend/package.json +6 -6
  23. qalita/commands/pack.py +41 -23
  24. qalita/commands/source.py +5 -4
  25. qalita/commands/worker.py +72 -24
  26. qalita/internal/request.py +4 -1
  27. qalita/internal/utils.py +178 -20
  28. qalita/web/blueprints/context.py +2 -1
  29. qalita/web/blueprints/dashboard.py +14 -5
  30. qalita/web/blueprints/sources.py +24 -6
  31. qalita/web/blueprints/workers.py +18 -4
  32. {qalita-2.5.3.dist-info → qalita-2.5.4.dist-info}/METADATA +2 -2
  33. {qalita-2.5.3.dist-info → qalita-2.5.4.dist-info}/RECORD +38 -37
  34. qalita/_frontend/node_modules/react/cjs/react-jsx-dev-runtime.production.min.js +0 -10
  35. qalita/_frontend/node_modules/react/cjs/react-jsx-runtime.production.min.js +0 -11
  36. qalita/_frontend/node_modules/react/cjs/react.production.min.js +0 -26
  37. qalita/_frontend/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.min.js +0 -93
  38. qalita/_frontend/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.min.js +0 -101
  39. qalita/_frontend/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js +0 -96
  40. qalita/_frontend/node_modules/react-dom/cjs/react-dom-server.node.production.min.js +0 -102
  41. qalita/_frontend/node_modules/react-dom/cjs/react-dom.production.min.js +0 -322
  42. qalita/_frontend/node_modules/scheduler/cjs/scheduler.development.js +0 -634
  43. qalita/_frontend/node_modules/scheduler/cjs/scheduler.production.min.js +0 -19
  44. qalita/_frontend/node_modules/scheduler/index.js +0 -7
  45. qalita/_frontend/node_modules/scheduler/package.json +0 -36
  46. /qalita/_frontend/.next/static/{fm8OzItmoekYnFcSZ5R8j → X4_AlYMbCyee-ZVLjCYMg}/_buildManifest.js +0 -0
  47. /qalita/_frontend/.next/static/{fm8OzItmoekYnFcSZ5R8j → X4_AlYMbCyee-ZVLjCYMg}/_ssgManifest.js +0 -0
  48. {qalita-2.5.3.dist-info → qalita-2.5.4.dist-info}/WHEEL +0 -0
  49. {qalita-2.5.3.dist-info → qalita-2.5.4.dist-info}/entry_points.txt +0 -0
  50. {qalita-2.5.3.dist-info → qalita-2.5.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,210 @@
1
+ /**
2
+ * @license React
3
+ * react-dom.production.js
4
+ *
5
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */
10
+
11
+ "use strict";
12
+ var React = require("react");
13
+ function formatProdErrorMessage(code) {
14
+ var url = "https://react.dev/errors/" + code;
15
+ if (1 < arguments.length) {
16
+ url += "?args[]=" + encodeURIComponent(arguments[1]);
17
+ for (var i = 2; i < arguments.length; i++)
18
+ url += "&args[]=" + encodeURIComponent(arguments[i]);
19
+ }
20
+ return (
21
+ "Minified React error #" +
22
+ code +
23
+ "; visit " +
24
+ url +
25
+ " for the full message or use the non-minified dev environment for full errors and additional helpful warnings."
26
+ );
27
+ }
28
+ function noop() {}
29
+ var Internals = {
30
+ d: {
31
+ f: noop,
32
+ r: function () {
33
+ throw Error(formatProdErrorMessage(522));
34
+ },
35
+ D: noop,
36
+ C: noop,
37
+ L: noop,
38
+ m: noop,
39
+ X: noop,
40
+ S: noop,
41
+ M: noop
42
+ },
43
+ p: 0,
44
+ findDOMNode: null
45
+ },
46
+ REACT_PORTAL_TYPE = Symbol.for("react.portal");
47
+ function createPortal$1(children, containerInfo, implementation) {
48
+ var key =
49
+ 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null;
50
+ return {
51
+ $$typeof: REACT_PORTAL_TYPE,
52
+ key: null == key ? null : "" + key,
53
+ children: children,
54
+ containerInfo: containerInfo,
55
+ implementation: implementation
56
+ };
57
+ }
58
+ var ReactSharedInternals =
59
+ React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
60
+ function getCrossOriginStringAs(as, input) {
61
+ if ("font" === as) return "";
62
+ if ("string" === typeof input)
63
+ return "use-credentials" === input ? input : "";
64
+ }
65
+ exports.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE =
66
+ Internals;
67
+ exports.createPortal = function (children, container) {
68
+ var key =
69
+ 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null;
70
+ if (
71
+ !container ||
72
+ (1 !== container.nodeType &&
73
+ 9 !== container.nodeType &&
74
+ 11 !== container.nodeType)
75
+ )
76
+ throw Error(formatProdErrorMessage(299));
77
+ return createPortal$1(children, container, null, key);
78
+ };
79
+ exports.flushSync = function (fn) {
80
+ var previousTransition = ReactSharedInternals.T,
81
+ previousUpdatePriority = Internals.p;
82
+ try {
83
+ if (((ReactSharedInternals.T = null), (Internals.p = 2), fn)) return fn();
84
+ } finally {
85
+ (ReactSharedInternals.T = previousTransition),
86
+ (Internals.p = previousUpdatePriority),
87
+ Internals.d.f();
88
+ }
89
+ };
90
+ exports.preconnect = function (href, options) {
91
+ "string" === typeof href &&
92
+ (options
93
+ ? ((options = options.crossOrigin),
94
+ (options =
95
+ "string" === typeof options
96
+ ? "use-credentials" === options
97
+ ? options
98
+ : ""
99
+ : void 0))
100
+ : (options = null),
101
+ Internals.d.C(href, options));
102
+ };
103
+ exports.prefetchDNS = function (href) {
104
+ "string" === typeof href && Internals.d.D(href);
105
+ };
106
+ exports.preinit = function (href, options) {
107
+ if ("string" === typeof href && options && "string" === typeof options.as) {
108
+ var as = options.as,
109
+ crossOrigin = getCrossOriginStringAs(as, options.crossOrigin),
110
+ integrity =
111
+ "string" === typeof options.integrity ? options.integrity : void 0,
112
+ fetchPriority =
113
+ "string" === typeof options.fetchPriority
114
+ ? options.fetchPriority
115
+ : void 0;
116
+ "style" === as
117
+ ? Internals.d.S(
118
+ href,
119
+ "string" === typeof options.precedence ? options.precedence : void 0,
120
+ {
121
+ crossOrigin: crossOrigin,
122
+ integrity: integrity,
123
+ fetchPriority: fetchPriority
124
+ }
125
+ )
126
+ : "script" === as &&
127
+ Internals.d.X(href, {
128
+ crossOrigin: crossOrigin,
129
+ integrity: integrity,
130
+ fetchPriority: fetchPriority,
131
+ nonce: "string" === typeof options.nonce ? options.nonce : void 0
132
+ });
133
+ }
134
+ };
135
+ exports.preinitModule = function (href, options) {
136
+ if ("string" === typeof href)
137
+ if ("object" === typeof options && null !== options) {
138
+ if (null == options.as || "script" === options.as) {
139
+ var crossOrigin = getCrossOriginStringAs(
140
+ options.as,
141
+ options.crossOrigin
142
+ );
143
+ Internals.d.M(href, {
144
+ crossOrigin: crossOrigin,
145
+ integrity:
146
+ "string" === typeof options.integrity ? options.integrity : void 0,
147
+ nonce: "string" === typeof options.nonce ? options.nonce : void 0
148
+ });
149
+ }
150
+ } else null == options && Internals.d.M(href);
151
+ };
152
+ exports.preload = function (href, options) {
153
+ if (
154
+ "string" === typeof href &&
155
+ "object" === typeof options &&
156
+ null !== options &&
157
+ "string" === typeof options.as
158
+ ) {
159
+ var as = options.as,
160
+ crossOrigin = getCrossOriginStringAs(as, options.crossOrigin);
161
+ Internals.d.L(href, as, {
162
+ crossOrigin: crossOrigin,
163
+ integrity:
164
+ "string" === typeof options.integrity ? options.integrity : void 0,
165
+ nonce: "string" === typeof options.nonce ? options.nonce : void 0,
166
+ type: "string" === typeof options.type ? options.type : void 0,
167
+ fetchPriority:
168
+ "string" === typeof options.fetchPriority
169
+ ? options.fetchPriority
170
+ : void 0,
171
+ referrerPolicy:
172
+ "string" === typeof options.referrerPolicy
173
+ ? options.referrerPolicy
174
+ : void 0,
175
+ imageSrcSet:
176
+ "string" === typeof options.imageSrcSet ? options.imageSrcSet : void 0,
177
+ imageSizes:
178
+ "string" === typeof options.imageSizes ? options.imageSizes : void 0,
179
+ media: "string" === typeof options.media ? options.media : void 0
180
+ });
181
+ }
182
+ };
183
+ exports.preloadModule = function (href, options) {
184
+ if ("string" === typeof href)
185
+ if (options) {
186
+ var crossOrigin = getCrossOriginStringAs(options.as, options.crossOrigin);
187
+ Internals.d.m(href, {
188
+ as:
189
+ "string" === typeof options.as && "script" !== options.as
190
+ ? options.as
191
+ : void 0,
192
+ crossOrigin: crossOrigin,
193
+ integrity:
194
+ "string" === typeof options.integrity ? options.integrity : void 0
195
+ });
196
+ } else Internals.d.m(href);
197
+ };
198
+ exports.requestFormReset = function (form) {
199
+ Internals.d.r(form);
200
+ };
201
+ exports.unstable_batchedUpdates = function (fn, a) {
202
+ return fn(a);
203
+ };
204
+ exports.useFormState = function (action, initialState, permalink) {
205
+ return ReactSharedInternals.H.useFormState(action, initialState, permalink);
206
+ };
207
+ exports.useFormStatus = function () {
208
+ return ReactSharedInternals.H.useHostTransitionStatus();
209
+ };
210
+ exports.version = "19.2.3";
@@ -32,7 +32,7 @@ if (process.env.NODE_ENV === 'production') {
32
32
  // DCE check should happen before ReactDOM bundle executes so that
33
33
  // DevTools can report bad minification during injection.
34
34
  checkDCE();
35
- module.exports = require('./cjs/react-dom.production.min.js');
35
+ module.exports = require('./cjs/react-dom.production.js');
36
36
  } else {
37
37
  module.exports = require('./cjs/react-dom.development.js');
38
38
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-dom",
3
- "version": "18.3.1",
3
+ "version": "19.2.3",
4
4
  "description": "React package for working with the DOM.",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -15,48 +15,103 @@
15
15
  "bugs": {
16
16
  "url": "https://github.com/facebook/react/issues"
17
17
  },
18
- "homepage": "https://reactjs.org/",
18
+ "homepage": "https://react.dev/",
19
19
  "dependencies": {
20
- "loose-envify": "^1.1.0",
21
- "scheduler": "^0.23.2"
20
+ "scheduler": "^0.27.0"
22
21
  },
23
22
  "peerDependencies": {
24
- "react": "^18.3.1"
23
+ "react": "^19.2.3"
25
24
  },
26
25
  "files": [
27
26
  "LICENSE",
28
27
  "README.md",
29
- "index.js",
30
28
  "client.js",
29
+ "client.react-server.js",
30
+ "index.js",
31
31
  "profiling.js",
32
- "server.js",
32
+ "profiling.react-server.js",
33
+ "react-dom.react-server.js",
33
34
  "server.browser.js",
35
+ "server.bun.js",
36
+ "server.edge.js",
37
+ "server.js",
34
38
  "server.node.js",
39
+ "server.react-server.js",
40
+ "static.browser.js",
41
+ "static.edge.js",
42
+ "static.js",
43
+ "static.node.js",
44
+ "static.react-server.js",
35
45
  "test-utils.js",
36
- "cjs/",
37
- "umd/"
46
+ "cjs/"
38
47
  ],
39
48
  "exports": {
40
- ".": "./index.js",
41
- "./client": "./client.js",
49
+ ".": {
50
+ "react-server": "./react-dom.react-server.js",
51
+ "default": "./index.js"
52
+ },
53
+ "./client": {
54
+ "react-server": "./client.react-server.js",
55
+ "default": "./client.js"
56
+ },
42
57
  "./server": {
58
+ "react-server": "./server.react-server.js",
59
+ "workerd": "./server.edge.js",
60
+ "bun": "./server.bun.js",
43
61
  "deno": "./server.browser.js",
44
62
  "worker": "./server.browser.js",
63
+ "node": "./server.node.js",
64
+ "edge-light": "./server.edge.js",
45
65
  "browser": "./server.browser.js",
46
66
  "default": "./server.node.js"
47
67
  },
48
- "./server.browser": "./server.browser.js",
49
- "./server.node": "./server.node.js",
50
- "./profiling": "./profiling.js",
68
+ "./server.browser": {
69
+ "react-server": "./server.react-server.js",
70
+ "default": "./server.browser.js"
71
+ },
72
+ "./server.bun": {
73
+ "react-server": "./server.react-server.js",
74
+ "default": "./server.bun.js"
75
+ },
76
+ "./server.edge": {
77
+ "react-server": "./server.react-server.js",
78
+ "default": "./server.edge.js"
79
+ },
80
+ "./server.node": {
81
+ "react-server": "./server.react-server.js",
82
+ "default": "./server.node.js"
83
+ },
84
+ "./static": {
85
+ "react-server": "./static.react-server.js",
86
+ "workerd": "./static.edge.js",
87
+ "deno": "./static.browser.js",
88
+ "worker": "./static.browser.js",
89
+ "node": "./static.node.js",
90
+ "edge-light": "./static.edge.js",
91
+ "browser": "./static.browser.js",
92
+ "default": "./static.node.js"
93
+ },
94
+ "./static.browser": {
95
+ "react-server": "./static.react-server.js",
96
+ "default": "./static.browser.js"
97
+ },
98
+ "./static.edge": {
99
+ "react-server": "./static.react-server.js",
100
+ "default": "./static.edge.js"
101
+ },
102
+ "./static.node": {
103
+ "react-server": "./static.react-server.js",
104
+ "default": "./static.node.js"
105
+ },
106
+ "./profiling": {
107
+ "react-server": "./profiling.react-server.js",
108
+ "default": "./profiling.js"
109
+ },
51
110
  "./test-utils": "./test-utils.js",
52
111
  "./package.json": "./package.json"
53
112
  },
54
113
  "browser": {
55
- "./server.js": "./server.browser.js"
56
- },
57
- "browserify": {
58
- "transform": [
59
- "loose-envify"
60
- ]
114
+ "./server.js": "./server.browser.js",
115
+ "./static.js": "./static.browser.js"
61
116
  }
62
117
  }
@@ -2,8 +2,8 @@
2
2
 
3
3
  var l, s;
4
4
  if (process.env.NODE_ENV === 'production') {
5
- l = require('./cjs/react-dom-server-legacy.browser.production.min.js');
6
- s = require('./cjs/react-dom-server.browser.production.min.js');
5
+ l = require('./cjs/react-dom-server-legacy.browser.production.js');
6
+ s = require('./cjs/react-dom-server.browser.production.js');
7
7
  } else {
8
8
  l = require('./cjs/react-dom-server-legacy.browser.development.js');
9
9
  s = require('./cjs/react-dom-server.browser.development.js');
@@ -12,6 +12,5 @@ if (process.env.NODE_ENV === 'production') {
12
12
  exports.version = l.version;
13
13
  exports.renderToString = l.renderToString;
14
14
  exports.renderToStaticMarkup = l.renderToStaticMarkup;
15
- exports.renderToNodeStream = l.renderToNodeStream;
16
- exports.renderToStaticNodeStream = l.renderToStaticNodeStream;
17
15
  exports.renderToReadableStream = s.renderToReadableStream;
16
+ exports.resume = s.resume;
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ var b;
4
+ var l;
5
+ if (process.env.NODE_ENV === 'production') {
6
+ b = require('./cjs/react-dom-server.edge.production.js');
7
+ l = require('./cjs/react-dom-server-legacy.browser.production.js');
8
+ } else {
9
+ b = require('./cjs/react-dom-server.edge.development.js');
10
+ l = require('./cjs/react-dom-server-legacy.browser.development.js');
11
+ }
12
+
13
+ exports.version = b.version;
14
+ exports.renderToReadableStream = b.renderToReadableStream;
15
+ exports.renderToString = l.renderToString;
16
+ exports.renderToStaticMarkup = l.renderToStaticMarkup;
17
+ exports.resume = b.resume;
@@ -2,8 +2,8 @@
2
2
 
3
3
  var l, s;
4
4
  if (process.env.NODE_ENV === 'production') {
5
- l = require('./cjs/react-dom-server-legacy.node.production.min.js');
6
- s = require('./cjs/react-dom-server.node.production.min.js');
5
+ l = require('./cjs/react-dom-server-legacy.node.production.js');
6
+ s = require('./cjs/react-dom-server.node.production.js');
7
7
  } else {
8
8
  l = require('./cjs/react-dom-server-legacy.node.development.js');
9
9
  s = require('./cjs/react-dom-server.node.development.js');
@@ -12,6 +12,7 @@ if (process.env.NODE_ENV === 'production') {
12
12
  exports.version = l.version;
13
13
  exports.renderToString = l.renderToString;
14
14
  exports.renderToStaticMarkup = l.renderToStaticMarkup;
15
- exports.renderToNodeStream = l.renderToNodeStream;
16
- exports.renderToStaticNodeStream = l.renderToStaticNodeStream;
17
15
  exports.renderToPipeableStream = s.renderToPipeableStream;
16
+ exports.renderToReadableStream = s.renderToReadableStream;
17
+ exports.resumeToPipeableStream = s.resumeToPipeableStream;
18
+ exports.resume = s.resume;
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ var s;
4
+ if (process.env.NODE_ENV === 'production') {
5
+ s = require('./cjs/react-dom-server.node.production.js');
6
+ } else {
7
+ s = require('./cjs/react-dom-server.node.development.js');
8
+ }
9
+
10
+ exports.version = s.version;
11
+ exports.prerenderToNodeStream = s.prerenderToNodeStream;
12
+ exports.prerender = s.prerender;
13
+ exports.resumeAndPrerenderToNodeStream = s.resumeAndPrerenderToNodeStream;
14
+ exports.resumeAndPrerender = s.resumeAndPrerender;
@@ -10,16 +10,16 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "next": "16.0.10",
13
- "react": "^18.3.1",
14
- "react-dom": "^18.3.1",
15
- "react-markdown": "^9.0.1",
13
+ "react": "^19.2.3",
14
+ "react-dom": "^19.2.3",
15
+ "react-markdown": "^10.1.0",
16
16
  "remark-gfm": "^4.0.0",
17
17
  "socket.io-client": "^4.7.0"
18
18
  },
19
19
  "devDependencies": {
20
- "@types/node": "^20.14.0",
21
- "@types/react": "^18.3.3",
22
- "@types/react-dom": "^18.3.0",
20
+ "@types/node": "^25.0.3",
21
+ "@types/react": "^19.2.7",
22
+ "@types/react-dom": "^19.2.3",
23
23
  "autoprefixer": "^10.4.22",
24
24
  "postcss": "^8.5.6",
25
25
  "tailwindcss": "^3.4.18",
qalita/commands/pack.py CHANGED
@@ -17,7 +17,7 @@ from threading import Thread
17
17
  from tabulate import tabulate
18
18
  from qalita.internal.error_patterns import ERROR_PATTERNS
19
19
  from qalita.__main__ import pass_config
20
- from qalita.internal.utils import logger, make_tarfile, ask_confirmation, safe_path_join
20
+ from qalita.internal.utils import logger, make_tarfile, ask_confirmation, safe_path_join, validate_directory_path
21
21
  from qalita.internal.request import send_request
22
22
 
23
23
  loggerPack = logging.getLogger(__name__)
@@ -361,18 +361,22 @@ def validate_pack_directory(pack_directory: str) -> int:
361
361
  logger.info("------------- Pack Validation (directory) -------------")
362
362
  error_count = 0
363
363
 
364
- # Normalize and validate the pack directory path
365
- pack_directory = os.path.abspath(pack_directory)
366
- if not os.path.isdir(pack_directory):
367
- logger.error(f"Pack folder '{pack_directory}' does not exist.")
364
+ # Validate and normalize the pack directory path
365
+ # Use a new variable to clearly indicate sanitized path
366
+ # Security: validate_directory_path sanitizes the path before use
367
+ try:
368
+ validated_dir = validate_directory_path(pack_directory) # lgtm[py/path-injection]
369
+ except (ValueError, FileNotFoundError) as e:
370
+ logger.error(f"Pack folder validation failed: {e}")
368
371
  return 1
369
372
 
370
373
  mandatory_files = ["run.sh", "properties.yaml", "README.md"]
371
374
  properties = None
372
375
  for file in mandatory_files:
373
376
  # Use safe_path_join to prevent path traversal
377
+ # Security: safe_path_join validates path stays within base directory
374
378
  try:
375
- file_path = safe_path_join(pack_directory, file)
379
+ file_path = safe_path_join(validated_dir, file) # lgtm[py/path-injection]
376
380
  except ValueError as e:
377
381
  logger.error(f"Invalid file path: {e}")
378
382
  error_count += 1
@@ -408,8 +412,9 @@ def validate_pack_directory(pack_directory: str) -> int:
408
412
 
409
413
  # Try to persist potential visibility default if we could parse properties
410
414
  if properties is not None:
415
+ # Security: safe_path_join validates path stays within base directory
411
416
  try:
412
- props_path = safe_path_join(pack_directory, "properties.yaml")
417
+ props_path = safe_path_join(validated_dir, "properties.yaml") # lgtm[py/path-injection]
413
418
  with open(props_path, "w", encoding="utf-8") as f:
414
419
  yaml.dump(properties, f)
415
420
  except Exception:
@@ -472,13 +477,20 @@ def push_pack(api_url, registry_id, pack_name, pack_version, source_dir=None, co
472
477
 
473
478
  def load_pack_properties(pack_directory):
474
479
  """Loads the properties.yaml file from the specified pack directory."""
475
- # Normalize the pack directory path
476
- pack_directory = os.path.abspath(pack_directory)
480
+ # Validate and normalize the pack directory path
481
+ # Security: validate_directory_path sanitizes the path before use
477
482
  try:
478
- properties_file = safe_path_join(pack_directory, "properties.yaml")
479
- except ValueError as e:
483
+ validated_dir = validate_directory_path(pack_directory) # lgtm[py/path-injection]
484
+ except (ValueError, FileNotFoundError) as e:
480
485
  logger.error(f"Invalid pack directory path: {e}")
481
486
  return None
487
+
488
+ # Security: safe_path_join validates path stays within base directory
489
+ try:
490
+ properties_file = safe_path_join(validated_dir, "properties.yaml") # lgtm[py/path-injection]
491
+ except ValueError as e:
492
+ logger.error(f"Invalid properties file path: {e}")
493
+ return None
482
494
 
483
495
  if not os.path.exists(properties_file):
484
496
  logger.error(f"Pack properties file '{properties_file}' not found.")
@@ -498,9 +510,11 @@ def load_base64_encoded_image(base_dir, filename):
498
510
  base_dir: The base directory containing the file.
499
511
  filename: The name of the file to load.
500
512
  """
513
+ # Security: validate_directory_path and safe_path_join sanitize paths
501
514
  try:
502
- file_path = safe_path_join(base_dir, filename)
503
- except ValueError as e:
515
+ validated_dir = validate_directory_path(base_dir) # lgtm[py/path-injection]
516
+ file_path = safe_path_join(validated_dir, filename) # lgtm[py/path-injection]
517
+ except (ValueError, FileNotFoundError) as e:
504
518
  logger.error(f"Invalid file path: {e}")
505
519
  return ""
506
520
 
@@ -521,9 +535,11 @@ def load_base64_encoded_text(base_dir, filename):
521
535
  base_dir: The base directory containing the file.
522
536
  filename: The name of the file to load.
523
537
  """
538
+ # Security: validate_directory_path and safe_path_join sanitize paths
524
539
  try:
525
- file_path = safe_path_join(base_dir, filename)
526
- except ValueError as e:
540
+ validated_dir = validate_directory_path(base_dir) # lgtm[py/path-injection]
541
+ file_path = safe_path_join(validated_dir, filename) # lgtm[py/path-injection]
542
+ except (ValueError, FileNotFoundError) as e:
527
543
  logger.error(f"Invalid file path: {e}")
528
544
  return ""
529
545
 
@@ -544,9 +560,11 @@ def load_json_config(base_dir, filename):
544
560
  base_dir: The base directory containing the file.
545
561
  filename: The name of the file to load.
546
562
  """
563
+ # Security: validate_directory_path and safe_path_join sanitize paths
547
564
  try:
548
- file_path = safe_path_join(base_dir, filename)
549
- except ValueError as e:
565
+ validated_dir = validate_directory_path(base_dir) # lgtm[py/path-injection]
566
+ file_path = safe_path_join(validated_dir, filename) # lgtm[py/path-injection]
567
+ except (ValueError, FileNotFoundError) as e:
550
568
  logger.error(f"Invalid file path: {e}")
551
569
  return {}
552
570
 
@@ -897,12 +915,12 @@ def push_from_directory(config, pack_directory):
897
915
  logger.error(msg)
898
916
  return False, msg
899
917
 
900
- # Normalize and validate the path
901
- pack_directory = os.path.normpath(os.path.abspath(pack_directory))
902
-
903
- # Ensure the directory exists and is actually a directory
904
- if not os.path.isdir(pack_directory):
905
- msg = f"Pack directory '{pack_directory}' does not exist."
918
+ # Validate and normalize the path using secure validation
919
+ # Security: validate_directory_path sanitizes the path before use
920
+ try:
921
+ pack_directory = validate_directory_path(pack_directory) # lgtm[py/path-injection]
922
+ except (ValueError, FileNotFoundError) as e:
923
+ msg = f"Pack directory validation failed: {e}"
906
924
  logger.error(msg)
907
925
  return False, msg
908
926
 
qalita/commands/source.py CHANGED
@@ -7,7 +7,7 @@ import click
7
7
  from tabulate import tabulate
8
8
 
9
9
  from qalita.__main__ import pass_config
10
- from qalita.internal.utils import logger, ask_confirmation, test_connection, safe_path_check
10
+ from qalita.internal.utils import logger, ask_confirmation, test_connection, safe_path_check, validate_file_path
11
11
  from qalita.internal.request import send_api_request
12
12
 
13
13
 
@@ -165,13 +165,14 @@ def validate_source(config):
165
165
  else:
166
166
  # check for read access to path
167
167
  try:
168
- path = safe_path_check(source["config"]["path"])
169
- if not os.access(path, os.R_OK):
168
+ # Security: validate_file_path sanitizes the path before use
169
+ validated_path = validate_file_path(source["config"]["path"]) # lgtm[py/path-injection]
170
+ if not os.access(validated_path, os.R_OK):
170
171
  logger.error(
171
172
  f"Source [{source['name']}] has a path in config, but it cannot be accessed"
172
173
  )
173
174
  is_source_valid = False
174
- except ValueError as e:
175
+ except (ValueError, FileNotFoundError) as e:
175
176
  logger.error(f"Source [{source['name']}] has an invalid path: {e}")
176
177
  is_source_valid = False
177
178