@sun-asterisk/sunlint 1.3.9 → 1.3.11
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.
- package/CHANGELOG.md +91 -1
- package/README.md +62 -0
- package/config/rules/enhanced-rules-registry.json +18 -0
- package/core/cli-action-handler.js +30 -1
- package/core/cli-program.js +5 -1
- package/core/output-service.js +160 -3
- package/core/scoring-service.js +169 -0
- package/core/semantic-engine.js +4 -2
- package/core/summary-report-service.js +189 -0
- package/core/upload-service.js +282 -0
- package/docs/QUALITY_SCORING_GUIDE.md +397 -0
- package/package.json +1 -1
- package/rules/common/C024_no_scatter_hardcoded_constants/symbol-based-analyzer.js +116 -10
- package/rules/common/C060_no_override_superclass/analyzer.js +180 -0
- package/rules/common/C060_no_override_superclass/config.json +50 -0
- package/rules/common/C060_no_override_superclass/symbol-based-analyzer.js +220 -0
- package/rules/index.js +1 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summary Report Service
|
|
3
|
+
* Generate summary reports for CI/CD and management dashboards
|
|
4
|
+
* Following Rule C005: Single responsibility - handle summary report generation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { execSync } = require('child_process');
|
|
10
|
+
|
|
11
|
+
class SummaryReportService {
|
|
12
|
+
constructor() {}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get Git repository information
|
|
16
|
+
* @param {string} cwd - Working directory
|
|
17
|
+
* @returns {Object} Git info including repository URL, branch, and commit hash
|
|
18
|
+
*/
|
|
19
|
+
getGitInfo(cwd = process.cwd()) {
|
|
20
|
+
const gitInfo = {
|
|
21
|
+
repository_url: null,
|
|
22
|
+
branch: null,
|
|
23
|
+
commit_hash: null
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Check if it's a git repository
|
|
28
|
+
execSync('git rev-parse --git-dir', { cwd, stdio: 'ignore' });
|
|
29
|
+
|
|
30
|
+
// Get repository URL (prefer origin)
|
|
31
|
+
try {
|
|
32
|
+
const remoteUrl = execSync('git config --get remote.origin.url', { cwd, encoding: 'utf8' }).trim();
|
|
33
|
+
// Convert SSH URL to HTTPS URL if needed
|
|
34
|
+
if (remoteUrl.startsWith('git@')) {
|
|
35
|
+
gitInfo.repository_url = remoteUrl
|
|
36
|
+
.replace('git@', 'https://')
|
|
37
|
+
.replace('.com:', '.com/')
|
|
38
|
+
.replace('.git', '');
|
|
39
|
+
} else {
|
|
40
|
+
gitInfo.repository_url = remoteUrl.replace('.git', '');
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
// No remote configured
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get current branch
|
|
47
|
+
try {
|
|
48
|
+
gitInfo.branch = execSync('git rev-parse --abbrev-ref HEAD', { cwd, encoding: 'utf8' }).trim();
|
|
49
|
+
} catch (error) {
|
|
50
|
+
// Can't get branch
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Get current commit hash
|
|
54
|
+
try {
|
|
55
|
+
gitInfo.commit_hash = execSync('git rev-parse HEAD', { cwd, encoding: 'utf8' }).trim();
|
|
56
|
+
} catch (error) {
|
|
57
|
+
// Can't get commit hash
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
// Not a git repository - return nulls
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return gitInfo;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Generate summary report from violations
|
|
68
|
+
* @param {Array} violations - Array of violations
|
|
69
|
+
* @param {Object} scoringSummary - Scoring summary with score and metrics
|
|
70
|
+
* @param {Object} options - Additional options
|
|
71
|
+
* @returns {Object} Summary report in JSON format
|
|
72
|
+
*/
|
|
73
|
+
generateSummaryReport(violations, scoringSummary, options = {}) {
|
|
74
|
+
// Get Git information
|
|
75
|
+
const gitInfo = this.getGitInfo(options.cwd);
|
|
76
|
+
|
|
77
|
+
// Override with environment variables if available (from CI/CD)
|
|
78
|
+
const repository_url = process.env.GITHUB_REPOSITORY
|
|
79
|
+
? `https://github.com/${process.env.GITHUB_REPOSITORY}`
|
|
80
|
+
: gitInfo.repository_url;
|
|
81
|
+
|
|
82
|
+
const branch = process.env.GITHUB_REF_NAME || gitInfo.branch;
|
|
83
|
+
const commit_hash = process.env.GITHUB_SHA || gitInfo.commit_hash;
|
|
84
|
+
|
|
85
|
+
// Count violations by rule
|
|
86
|
+
const violationsByRule = {};
|
|
87
|
+
violations.forEach(violation => {
|
|
88
|
+
const ruleId = violation.ruleId || 'unknown';
|
|
89
|
+
if (!violationsByRule[ruleId]) {
|
|
90
|
+
violationsByRule[ruleId] = {
|
|
91
|
+
rule_code: ruleId,
|
|
92
|
+
count: 0,
|
|
93
|
+
severity: violation.severity || 'warning'
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
violationsByRule[ruleId].count++;
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Convert to array and sort by count (descending)
|
|
100
|
+
const violationsSummary = Object.values(violationsByRule)
|
|
101
|
+
.sort((a, b) => b.count - a.count);
|
|
102
|
+
|
|
103
|
+
// Build the summary report
|
|
104
|
+
const summaryReport = {
|
|
105
|
+
metadata: {
|
|
106
|
+
generated_at: new Date().toISOString(),
|
|
107
|
+
tool: 'SunLint',
|
|
108
|
+
version: options.version || '1.3.9',
|
|
109
|
+
analysis_duration_ms: options.duration || 0
|
|
110
|
+
},
|
|
111
|
+
repository: {
|
|
112
|
+
repository_url,
|
|
113
|
+
branch,
|
|
114
|
+
commit_hash
|
|
115
|
+
},
|
|
116
|
+
quality: {
|
|
117
|
+
score: scoringSummary.score,
|
|
118
|
+
grade: scoringSummary.grade,
|
|
119
|
+
metrics: scoringSummary.metrics
|
|
120
|
+
},
|
|
121
|
+
violations: {
|
|
122
|
+
total: violations.length,
|
|
123
|
+
by_severity: {
|
|
124
|
+
errors: scoringSummary.metrics.errors,
|
|
125
|
+
warnings: scoringSummary.metrics.warnings
|
|
126
|
+
},
|
|
127
|
+
by_rule: violationsSummary
|
|
128
|
+
},
|
|
129
|
+
analysis: {
|
|
130
|
+
files_analyzed: options.filesAnalyzed || 0,
|
|
131
|
+
rules_checked: scoringSummary.metrics.rulesChecked,
|
|
132
|
+
lines_of_code: scoringSummary.metrics.linesOfCode
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
return summaryReport;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Generate summary report and save to file
|
|
141
|
+
* @param {Array} violations - Array of violations
|
|
142
|
+
* @param {Object} scoringSummary - Scoring summary
|
|
143
|
+
* @param {string} outputPath - Output file path
|
|
144
|
+
* @param {Object} options - Additional options
|
|
145
|
+
*/
|
|
146
|
+
saveSummaryReport(violations, scoringSummary, outputPath, options = {}) {
|
|
147
|
+
const summaryReport = this.generateSummaryReport(violations, scoringSummary, options);
|
|
148
|
+
|
|
149
|
+
// Ensure directory exists
|
|
150
|
+
const dir = path.dirname(outputPath);
|
|
151
|
+
if (!fs.existsSync(dir)) {
|
|
152
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Write to file with pretty formatting
|
|
156
|
+
fs.writeFileSync(outputPath, JSON.stringify(summaryReport, null, 2), 'utf8');
|
|
157
|
+
|
|
158
|
+
return summaryReport;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Generate a simple text summary for console display
|
|
163
|
+
* @param {Object} summaryReport - Summary report object
|
|
164
|
+
* @returns {string} Formatted text summary
|
|
165
|
+
*/
|
|
166
|
+
formatTextSummary(summaryReport) {
|
|
167
|
+
const { quality, violations, analysis } = summaryReport;
|
|
168
|
+
|
|
169
|
+
let output = '\n📊 Quality Summary Report\n';
|
|
170
|
+
output += '━'.repeat(50) + '\n';
|
|
171
|
+
output += `📈 Quality Score: ${quality.score} (Grade: ${quality.grade})\n`;
|
|
172
|
+
output += `📁 Files Analyzed: ${analysis.files_analyzed}\n`;
|
|
173
|
+
output += `📋 Rules Checked: ${analysis.rules_checked}\n`;
|
|
174
|
+
output += `📏 Lines of Code: ${analysis.lines_of_code.toLocaleString()}\n`;
|
|
175
|
+
output += `⚠️ Total Violations: ${violations.total} (${violations.by_severity.errors} errors, ${violations.by_severity.warnings} warnings)\n`;
|
|
176
|
+
output += `📊 Violations per KLOC: ${quality.metrics.violationsPerKLOC}\n`;
|
|
177
|
+
|
|
178
|
+
if (violations.by_rule.length > 0) {
|
|
179
|
+
output += '\n🔍 Top Violations by Rule:\n';
|
|
180
|
+
violations.by_rule.slice(0, 10).forEach((item, index) => {
|
|
181
|
+
output += ` ${index + 1}. ${item.rule_code}: ${item.count} violations (${item.severity})\n`;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return output;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
module.exports = SummaryReportService;
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upload Service
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const crypto = require('crypto');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
|
|
11
|
+
class UploadService {
|
|
12
|
+
/**
|
|
13
|
+
* Upload report file to API endpoint using curl
|
|
14
|
+
*/
|
|
15
|
+
async uploadReportToApi(filePath, apiUrl, options = {}) {
|
|
16
|
+
try {
|
|
17
|
+
this.validateUploadParameters(filePath, apiUrl);
|
|
18
|
+
|
|
19
|
+
const oidcToken = this.getOidcToken();
|
|
20
|
+
console.log(chalk.blue(`📤 Uploading report to: ${apiUrl}`));
|
|
21
|
+
|
|
22
|
+
if (oidcToken) {
|
|
23
|
+
console.log(chalk.green(`🔐 Using OIDC authentication (CI detected)`));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const uploadResult = await this.executeUploadCommand(filePath, apiUrl, options);
|
|
27
|
+
|
|
28
|
+
console.log(chalk.green(`✅ Report uploaded successfully!`));
|
|
29
|
+
return {
|
|
30
|
+
success: true,
|
|
31
|
+
url: apiUrl,
|
|
32
|
+
filePath: filePath,
|
|
33
|
+
response: uploadResult.response,
|
|
34
|
+
statusCode: uploadResult.statusCode
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
} catch (error) {
|
|
38
|
+
const errorContext = {
|
|
39
|
+
filePath,
|
|
40
|
+
apiUrl,
|
|
41
|
+
error: error.message,
|
|
42
|
+
timestamp: new Date().toISOString()
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
console.error(chalk.red('❌ Upload failed:'), error.message);
|
|
46
|
+
|
|
47
|
+
if (options.verbose || options.debug) {
|
|
48
|
+
console.error('Upload error context:', errorContext);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
success: false,
|
|
53
|
+
url: apiUrl,
|
|
54
|
+
filePath: filePath,
|
|
55
|
+
error: error.message,
|
|
56
|
+
errorContext
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Validate upload parameters
|
|
63
|
+
*/
|
|
64
|
+
validateUploadParameters(filePath, apiUrl) {
|
|
65
|
+
if (!filePath) {
|
|
66
|
+
throw new Error('File path is required for upload');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!apiUrl) {
|
|
70
|
+
throw new Error('API URL is required for upload');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!fs.existsSync(filePath)) {
|
|
74
|
+
throw new Error(`Upload file does not exist: ${filePath}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Basic URL validation
|
|
78
|
+
try {
|
|
79
|
+
new URL(apiUrl);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
throw new Error(`Invalid API URL format: ${apiUrl}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Execute curl command to upload file
|
|
87
|
+
*/
|
|
88
|
+
async executeUploadCommand(filePath, apiUrl, options = {}) {
|
|
89
|
+
const fileName = path.basename(filePath);
|
|
90
|
+
const timeout = options.timeout || 30; // 30 seconds default timeout
|
|
91
|
+
|
|
92
|
+
// Build curl command
|
|
93
|
+
const curlCommand = this.buildCurlCommand(filePath, apiUrl, fileName, timeout);
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
// Execute curl command synchronously for simplicity
|
|
97
|
+
const output = execSync(curlCommand, {
|
|
98
|
+
encoding: 'utf8',
|
|
99
|
+
maxBuffer: 1024 * 1024, // 1MB buffer
|
|
100
|
+
timeout: timeout * 1000 // Convert to milliseconds
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Parse response if possible
|
|
104
|
+
let response = output.trim();
|
|
105
|
+
let statusCode = null;
|
|
106
|
+
|
|
107
|
+
// Try to extract status code from curl verbose output
|
|
108
|
+
const statusMatch = response.match(/HTTP\/[\d.]+\s+(\d{3})/);
|
|
109
|
+
if (statusMatch) {
|
|
110
|
+
statusCode = parseInt(statusMatch[1]);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
response: response,
|
|
115
|
+
statusCode: statusCode
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
} catch (error) {
|
|
119
|
+
throw new Error(`curl command failed: ${error.message}. Command: ${curlCommand}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Build curl command for file upload
|
|
125
|
+
*/
|
|
126
|
+
buildCurlCommand(filePath, apiUrl, fileName, timeout) {
|
|
127
|
+
const curlOptions = [
|
|
128
|
+
'curl',
|
|
129
|
+
'-X POST',
|
|
130
|
+
`--connect-timeout ${timeout}`,
|
|
131
|
+
`--max-time ${timeout}`,
|
|
132
|
+
'-H "Content-Type: application/json"',
|
|
133
|
+
'-H "User-Agent: SunLint-Report-Uploader/1.0"'
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
// Add Idempotency-Key for safe retries
|
|
137
|
+
const idempotencyKey = this.generateIdempotencyKey(filePath);
|
|
138
|
+
curlOptions.push(`-H "Idempotency-Key: ${idempotencyKey}"`);
|
|
139
|
+
|
|
140
|
+
// Add OIDC token if running in CI environment
|
|
141
|
+
const oidcToken = this.getOidcToken();
|
|
142
|
+
if (oidcToken) {
|
|
143
|
+
curlOptions.push(`-H "Authorization: Bearer ${oidcToken}"`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
curlOptions.push(
|
|
147
|
+
`--data-binary @"${filePath}"`,
|
|
148
|
+
`"${apiUrl}"`
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return curlOptions.join(' ');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Check if curl is available on system
|
|
156
|
+
*/
|
|
157
|
+
checkCurlAvailability() {
|
|
158
|
+
try {
|
|
159
|
+
execSync('curl --version', { stdio: 'ignore' });
|
|
160
|
+
return true;
|
|
161
|
+
} catch (error) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get OIDC token from environment variables (for CI authentication)
|
|
168
|
+
*/
|
|
169
|
+
getOidcToken() {
|
|
170
|
+
// Try to get GitHub Actions OIDC token first (requires API call)
|
|
171
|
+
if (process.env.GITHUB_ACTIONS && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN && process.env.ACTIONS_ID_TOKEN_REQUEST_URL) {
|
|
172
|
+
try {
|
|
173
|
+
const githubToken = this.requestGitHubOidcToken();
|
|
174
|
+
if (githubToken) {
|
|
175
|
+
return githubToken;
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.log(chalk.yellow(`⚠️ Failed to get GitHub OIDC token: ${error.message}`));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Check if running in GitHub Actions without OIDC token
|
|
183
|
+
if (process.env.GITHUB_ACTIONS) {
|
|
184
|
+
console.log(chalk.yellow('⚠️ Running in GitHub Actions but no OIDC token available. Upload may require authentication.'));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Request OIDC token from GitHub Actions
|
|
192
|
+
*/
|
|
193
|
+
requestGitHubOidcToken() {
|
|
194
|
+
const requestToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
|
|
195
|
+
const requestUrl = process.env.ACTIONS_ID_TOKEN_REQUEST_URL;
|
|
196
|
+
|
|
197
|
+
if (!requestToken || !requestUrl) {
|
|
198
|
+
throw new Error('Missing GitHub OIDC request credentials');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
// Use curl to request OIDC token from GitHub with specific audience
|
|
203
|
+
const curlCommand = `curl -H "Authorization: bearer ${requestToken}" "${requestUrl}&audience=coding-standards-report-api"`;
|
|
204
|
+
|
|
205
|
+
const response = execSync(curlCommand, {
|
|
206
|
+
encoding: 'utf8',
|
|
207
|
+
timeout: 10000, // 10 second timeout
|
|
208
|
+
stdio: 'pipe'
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const responseData = JSON.parse(response);
|
|
212
|
+
|
|
213
|
+
if (responseData.value) {
|
|
214
|
+
return responseData.value;
|
|
215
|
+
} else {
|
|
216
|
+
throw new Error('No token in response');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
} catch (error) {
|
|
220
|
+
throw new Error(`GitHub OIDC request failed: ${error.message}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Generate idempotency key for safe retries
|
|
226
|
+
*/
|
|
227
|
+
generateIdempotencyKey(filePath) {
|
|
228
|
+
// Create deterministic key based on file content and timestamp
|
|
229
|
+
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
230
|
+
const timestamp = new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
|
|
231
|
+
|
|
232
|
+
// Include CI context for uniqueness across environments and attempts
|
|
233
|
+
const ciContext = process.env.GITHUB_ACTIONS ?
|
|
234
|
+
`${process.env.GITHUB_REPOSITORY || 'unknown'}-${process.env.GITHUB_RUN_ID || 'local'}-${process.env.GITHUB_RUN_ATTEMPT || '1'}` :
|
|
235
|
+
'local';
|
|
236
|
+
|
|
237
|
+
// Create hash from content + date + CI context + run attempt
|
|
238
|
+
const hashInput = `${fileContent}-${timestamp}-${ciContext}`;
|
|
239
|
+
const hash = crypto.createHash('sha256').update(hashInput).digest('hex');
|
|
240
|
+
|
|
241
|
+
// Return first 32 characters for reasonable key length
|
|
242
|
+
return `sunlint-${hash.substring(0, 24)}`;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Validate API endpoint accessibility
|
|
247
|
+
*/
|
|
248
|
+
async validateApiEndpoint(apiUrl, options = {}) {
|
|
249
|
+
try {
|
|
250
|
+
const timeout = options.timeout || 10;
|
|
251
|
+
|
|
252
|
+
// Build command with auth header if available
|
|
253
|
+
let testCommand = `curl -X HEAD --connect-timeout ${timeout} --max-time ${timeout} -s -o /dev/null -w "%{http_code}"`;
|
|
254
|
+
|
|
255
|
+
const oidcToken = this.getOidcToken();
|
|
256
|
+
if (oidcToken) {
|
|
257
|
+
testCommand += ` -H "Authorization: Bearer ${oidcToken}"`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
testCommand += ` "${apiUrl}"`;
|
|
261
|
+
|
|
262
|
+
const statusCode = execSync(testCommand, { encoding: 'utf8' }).trim();
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
accessible: true,
|
|
266
|
+
statusCode: parseInt(statusCode),
|
|
267
|
+
url: apiUrl,
|
|
268
|
+
authenticated: !!oidcToken
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
} catch (error) {
|
|
272
|
+
return {
|
|
273
|
+
accessible: false,
|
|
274
|
+
error: error.message,
|
|
275
|
+
url: apiUrl,
|
|
276
|
+
authenticated: !!this.getOidcToken()
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
module.exports = UploadService;
|