• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

suculent / thinx-device-api / #252646772

01 Nov 2025 04:02PM UTC coverage: 71.771% (-0.08%) from 71.849%
#252646772

push

suculent
Merge commit '<a class=hub.com/suculent/thinx-device-api/commit/b24b8ed40847c1bd5e5dd481cc80d145edbdacae">b24b8ed40' into thinx-staging

* commit 'b24b8ed40847c1bd5e5dd481cc80d145edbdacae':
  fix: package.json & package-lock.json to reduce vulnerabilities
  master merge
  base update for vulnerability scan update
  generated openapi spec
  merged arduino docker build and transformer
  broker update/sync
  component update
  broker recreated as submodule (to be built separately using CI)
  removed broker to be recreated as submodule (to be built separately using CI)
  submodule update
  dependencies updated, push for rescanning

# Conflicts:
#	base
#	package-lock.json
#	services/console
#	services/transformer
#	services/worker

1861 of 3538 branches covered (52.6%)

Branch coverage included in aggregate %.

8207 of 10490 relevant lines covered (78.24%)

7.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.83
/lib/thinx/git.js
1
// Git Shell Manager
2

3
const Globals = require("./globals.js");
1✔
4
const app_config = Globals.app_config();
1✔
5
const fs = require("fs-extra");
1✔
6
const exec = require("child_process");
1✔
7

8
const valid_responses = [
1✔
9
        "already exists and is not an empty",
10
        "FETCH_HEAD",
11
        "up-to-date",
12
        "Checking out files: 100%",
13
        "done.",
14
        "Cloning into"
15
];
16
module.exports = class Git {
1✔
17

18
        responseWhiteBlacklist(rstring) {
19
                let success;
20
                for (let index in valid_responses) {
15✔
21
                        if (rstring.indexOf(valid_responses[index]) != -1) {
90✔
22
                                success = true;
14✔
23
                                console.log("Success expected with valid response ", valid_responses[index]);
14✔
24
                                break;
14✔
25
                        }
26
                }
27

28
                // blacklist
29
                let invalid_responses = [ "fatal" ];
15✔
30
                for (let index in invalid_responses) {
15✔
31
                        if (rstring.indexOf(invalid_responses[index]) != -1) {
15✔
32
                                success = false;
2✔
33
                                console.log("Failure override due to invalid response ", invalid_responses[index]);
2✔
34
                                break;
2✔
35
                        }
36
                }
37
                return success;
15✔
38
        }
39

40
        checkResponse(rstring, local_path) {
41

42
                // whitelist (default response is '')
43
                let success = this.responseWhiteBlacklist(rstring);
15✔
44

45
                // the basefile must exist; local_path must be valid
46
                if ((success == false) && (typeof(local_path) !== "undefined")) {
15✔
47
                        if (!fs.existsSync(local_path)) return false;
2!
48
                        let basename_path = local_path + "/basename.json";
×
49
                        success = fs.existsSync(basename_path); // may throw! but does not work.
×
50
                        if (success) console.log(basename_path, "exists, success...");
×
51
                }
52

53
                console.log("[TODO TEST] Git response result", success);
13✔
54

55
                return success;
13✔
56
        }
57

58
        tryShellOp(cmd, local_path) {
59
                let result;
60
                try {
15✔
61
                        result = exec.execSync(cmd).toString().trim(); // lgtm [js/command-line-injection]
15✔
62
                        console.log("[git] exec result: '", result, "'");
13✔
63
                } catch (e) {
64
                        result = e.stdout.toString();
2✔
65
                        console.log("[ERROR] [git] exec result: '", result, "'");
2✔
66
                }
67
                return this.checkResponse(result, local_path);
15✔
68
        }
69

70
        askpath(keypath) {
71
                return keypath + ".sh";
42✔
72
        }
73

74
        create_askfile(keypath, password) {
75
                let path = this.askpath(keypath);
14✔
76
                let contents = `#!/usr/bin/env sh\necho "${password}"`;
14✔
77
                fs.writeFileSync(path, contents);
14✔
78
                fs.chmodSync(path, 0o700);
14✔
79
        }
80

81
        delete_askfile(keypath) {
82
                fs.removeSync(this.askpath(keypath));
14✔
83
        }
84

85
    fetch(owner, command, local_path) {
86
                // TODO: Fetch owner's key password (defaults to thinx now) and create askfile (should be per-user to allow parallelism, and deleted at the end)
87
                let success = false;
13✔
88
                let RSAKey = require("./rsakey"); let rsa = new RSAKey();
13✔
89
                let key_paths = rsa.getKeyPathsForOwner(owner);
13✔
90
                if ((typeof(key_paths) === "undefined") || (key_paths.length < 1)) {
13!
91
                        console.log("ℹ️ [info] [git] no_rsa_keys_found");
×
92
                        return this.tryShellOp(command, local_path);
×
93
                } 
94
                
95
                // tries all keys until successful... may use last_successful_key first
96
                for (var kindex in key_paths) {
13✔
97
                        let keypath = app_config.ssh_keys + "/" + key_paths[kindex];
14✔
98
                        let askpath = this.askpath(keypath);
14✔
99
                        var gfpfx = `ssh-agent sh -c 'DISPLAY=: SSH_ASKPASS=${askpath} GIT_ASKPASS=${askpath} ssh-add ${keypath} >/dev/null 2>&1; `;
14✔
100
                        let prefixed_command = gfpfx + command + "' 2>&1";
14✔
101
                        this.create_askfile(keypath, "thinx"); // TODO: per-owner/per-key keypass stored in Vault
14✔
102
                        success = this.tryShellOp(prefixed_command, local_path);
14✔
103
                        this.delete_askfile(keypath);
14✔
104
                        if (success) return success;
14✔
105
                }
106
                
107
                return success;
1✔
108
        }
109

110
        // WHY IS THIS HERE? WHY IS THIS NOT FETCH? TO TRY WITHOUT KEY? FETCH WILL SUCCEED ANYWAY (IF ANY KEY EXISTS)
111
        prefetch(GIT_PREFETCH) {
112
                console.log(`🔨 [debug] git prefetch command:\n ${GIT_PREFETCH}`);
×
113
                var result = "";
×
114
                try {
×
115
                        result = exec.execSync(GIT_PREFETCH).toString().replace("\n", "");
×
116
                        if (result !== "Already up to date.") {
×
117
                                console.log(`ℹ️ [info] [builder] git prefetch result: ${result}`);
×
118
                        }
119
                } catch (e) { console.log("⚠️ [warning] git prefetch not successful..."); }
×
120
                return result;
×
121
        }
122
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc