@docupace/pipeline 1.0.32 → 1.0.33-alpha-1
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/package.json +2 -2
- package/src/auth0/alias.js +36 -39
- package/src/auth0/cli.js +46 -15
- package/src/auth0/configure.js +230 -451
- package/src/auth0/export.js +43 -0
- package/src/auth0/metadata.js +124 -0
- package/src/auth0/vault.js +3 -3
- package/terraform/init.sh +21 -9
- package/terraform/plan.sh +12 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docupace/pipeline",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.33-alpha-1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@changesets/cli": "^2.27.10",
|
|
19
19
|
"@docupace/core-client": "^0.1.59",
|
|
20
|
-
"auth0-deploy-cli": "^
|
|
20
|
+
"auth0-deploy-cli": "^8.8.0",
|
|
21
21
|
"axios": "^1.7.9",
|
|
22
22
|
"commander": "^12.1.0",
|
|
23
23
|
"dotenv": "^16.4.7",
|
package/src/auth0/alias.js
CHANGED
|
@@ -1,75 +1,72 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
createAlias
|
|
5
|
-
} from '../next/alias.js';
|
|
3
|
+
import { createAlias } from '../next/alias.js';
|
|
6
4
|
|
|
7
|
-
import {getAuth0AuthToken} from './configure.js';
|
|
5
|
+
import { getAuth0AuthToken } from './configure.js';
|
|
8
6
|
|
|
9
|
-
import {
|
|
10
|
-
getVaultSecrets,
|
|
11
|
-
} from './vault.js';
|
|
7
|
+
import { getVaultSecrets } from './vault.js';
|
|
12
8
|
|
|
13
|
-
import {
|
|
14
|
-
getVaultSecretsConfigs,
|
|
15
|
-
} from '../next/config.js';
|
|
9
|
+
import { getVaultSecretsConfigs } from '../next/config.js';
|
|
16
10
|
|
|
17
|
-
import {
|
|
18
|
-
cloneEnvRepository,
|
|
19
|
-
readDeployConfig,
|
|
20
|
-
} from '../next/deploy.js';
|
|
11
|
+
import { cloneEnvRepository, readDeployConfig } from '../next/deploy.js';
|
|
21
12
|
|
|
22
|
-
export async function getCCAlias
|
|
13
|
+
export async function getCCAlias({ application, auth0Domain, auth0AuthToken }) {
|
|
23
14
|
console.log(`Forming alias name for application ${application}...`);
|
|
24
15
|
|
|
25
16
|
try {
|
|
26
|
-
const auth0Response = await axios.get(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
const auth0Response = await axios.get(
|
|
18
|
+
`https://${auth0Domain}/api/v2/clients`,
|
|
19
|
+
{
|
|
20
|
+
headers: { authorization: `Bearer ${auth0AuthToken}` },
|
|
21
|
+
},
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const appAuth0ClientIdData = auth0Response.data.find(
|
|
25
|
+
(client) => client.name === `${application}`,
|
|
26
|
+
);
|
|
31
27
|
const appAuth0ClientId = appAuth0ClientIdData.client_id;
|
|
32
28
|
|
|
33
29
|
console.log(`Client Credentials Alias: ${appAuth0ClientId}@clients`);
|
|
34
30
|
return `${appAuth0ClientId}@clients`;
|
|
35
31
|
} catch (err) {
|
|
36
|
-
console.error(
|
|
32
|
+
console.error(
|
|
33
|
+
`Failed to form alias name for application: ${application}: ${err.message}`,
|
|
34
|
+
);
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
export async function configureAlias(site, env, username, password, realm) {
|
|
41
|
-
|
|
42
39
|
console.log(`Creating alias for site: ${site} in env: ${env}`);
|
|
43
|
-
|
|
44
|
-
const commonSecretsPath = getVaultSecretsConfigs(site).commonSecretsPath;
|
|
45
|
-
console.log(`commonSecretsPath => ${commonSecretsPath}`)
|
|
46
|
-
const commonSecrets = await getVaultSecrets(commonSecretsPath);
|
|
47
|
-
|
|
48
40
|
// Site Common Secrets
|
|
49
|
-
const siteCommonSecretsPath =
|
|
50
|
-
|
|
41
|
+
const siteCommonSecretsPath =
|
|
42
|
+
getVaultSecretsConfigs(site).siteCommonSecretsPath;
|
|
43
|
+
console.log(`siteCommonSecretsPath => ${siteCommonSecretsPath}`);
|
|
51
44
|
const siteCommonSecrets = await getVaultSecrets(siteCommonSecretsPath);
|
|
52
45
|
|
|
53
|
-
const auth0Domain = `docupace-${env}-${site}.us.auth0.com
|
|
46
|
+
const auth0Domain = `docupace-${env}-${site}.us.auth0.com`;
|
|
54
47
|
const auth0ClientId = siteCommonSecrets.AUTH0_CLIENT_ID;
|
|
55
48
|
const auth0ClientSecret = siteCommonSecrets.AUTH0_CLIENT_SECRET;
|
|
56
|
-
const auth0Token = await getAuth0AuthToken(
|
|
49
|
+
const auth0Token = await getAuth0AuthToken(
|
|
50
|
+
auth0Domain,
|
|
51
|
+
auth0ClientId,
|
|
52
|
+
auth0ClientSecret,
|
|
53
|
+
);
|
|
57
54
|
|
|
58
55
|
await cloneEnvRepository(env);
|
|
59
56
|
|
|
60
|
-
const { deployConfig: deployGraphQLServerConfig} = await readDeployConfig(
|
|
57
|
+
const { deployConfig: deployGraphQLServerConfig } = await readDeployConfig(
|
|
58
|
+
'graphql-server',
|
|
59
|
+
env,
|
|
60
|
+
site,
|
|
61
|
+
'values',
|
|
62
|
+
);
|
|
61
63
|
const coreUrl = deployGraphQLServerConfig.graphqlServer.coreUrl;
|
|
62
64
|
|
|
63
65
|
const clientCredentialsAlias = await getCCAlias({
|
|
64
66
|
application: 'docupace-graphql-client-credentials',
|
|
65
67
|
auth0Domain: auth0Domain,
|
|
66
|
-
auth0AuthToken: auth0Token
|
|
68
|
+
auth0AuthToken: auth0Token,
|
|
67
69
|
});
|
|
68
70
|
|
|
69
|
-
await createAlias(
|
|
70
|
-
coreUrl,
|
|
71
|
-
username,
|
|
72
|
-
password,
|
|
73
|
-
realm,
|
|
74
|
-
clientCredentialsAlias);
|
|
71
|
+
await createAlias(coreUrl, username, password, realm, clientCredentialsAlias);
|
|
75
72
|
}
|
package/src/auth0/cli.js
CHANGED
|
@@ -1,34 +1,51 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { Command } from 'commander';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
} from './configure.js';
|
|
7
|
-
import {
|
|
8
|
-
getVaultSecrets
|
|
9
|
-
} from './vault.js'
|
|
4
|
+
import { configureFromSite } from './configure.js';
|
|
5
|
+
import { getVaultSecrets } from './vault.js';
|
|
10
6
|
|
|
11
7
|
import dotenv from 'dotenv';
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
} from
|
|
8
|
+
import { configureAlias } from './alias.js';
|
|
9
|
+
import { exportConf } from './export.js';
|
|
10
|
+
import { getAuth0Metadata } from './metadata.js';
|
|
15
11
|
|
|
16
12
|
dotenv.config({ path: ['.env.pipeline.local', 'config/.env.pipeline.local'] });
|
|
17
13
|
|
|
18
14
|
const program = new Command();
|
|
19
15
|
|
|
20
16
|
program
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
.command(
|
|
18
|
+
'configureFromSite <fromSite> <toSite> <fromEnv> <toEnv> <deployUI> <deployGraphQLServer> <useNewDomain>',
|
|
19
|
+
)
|
|
20
|
+
.description('Configure the Auth0 tenants in env for the given site')
|
|
21
|
+
.action(
|
|
22
|
+
async (
|
|
23
|
+
fromSite,
|
|
24
|
+
toSite,
|
|
25
|
+
fromEnv,
|
|
26
|
+
toEnv,
|
|
27
|
+
deployUI,
|
|
28
|
+
deployGraphQLServer,
|
|
29
|
+
useNewDomain,
|
|
30
|
+
) => {
|
|
31
|
+
await configureFromSite(
|
|
32
|
+
fromSite,
|
|
33
|
+
toSite,
|
|
34
|
+
fromEnv,
|
|
35
|
+
toEnv,
|
|
36
|
+
deployUI,
|
|
37
|
+
deployGraphQLServer,
|
|
38
|
+
useNewDomain,
|
|
39
|
+
);
|
|
40
|
+
},
|
|
41
|
+
);
|
|
26
42
|
|
|
27
43
|
program
|
|
28
44
|
.command('getVaultSecrets <vaultPath>')
|
|
29
45
|
.description('Get Secrets for Vault PATH')
|
|
30
46
|
.action(async (vaultPath) => {
|
|
31
|
-
await getVaultSecrets(vaultPath);
|
|
47
|
+
const data = await getVaultSecrets(vaultPath);
|
|
48
|
+
console.log(JSON.stringify(data, 'null', 2));
|
|
32
49
|
});
|
|
33
50
|
|
|
34
51
|
program
|
|
@@ -38,4 +55,18 @@ program
|
|
|
38
55
|
await configureAlias(site, env, username, password, realm);
|
|
39
56
|
});
|
|
40
57
|
|
|
58
|
+
program
|
|
59
|
+
.command('exportConf <site> <env>')
|
|
60
|
+
.description('Export Auth0 configuration for the given site')
|
|
61
|
+
.action(async (site, env) => {
|
|
62
|
+
await exportConf(site, env);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
program
|
|
66
|
+
.command('getAuth0Metadata <site> <env>')
|
|
67
|
+
.description('Get Auth0 metadata for the given site')
|
|
68
|
+
.action(async (site, env) => {
|
|
69
|
+
await getAuth0Metadata(site, env);
|
|
70
|
+
});
|
|
71
|
+
|
|
41
72
|
program.parse(process.argv);
|
package/src/auth0/configure.js
CHANGED
|
@@ -2,27 +2,15 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import axios from 'axios';
|
|
4
4
|
import crypto from 'crypto';
|
|
5
|
-
import { deploy } from 'auth0-deploy-cli';
|
|
6
|
-
import fl from 'fs/promises';
|
|
7
5
|
|
|
8
6
|
import {
|
|
9
7
|
cloneEnvRepository,
|
|
10
|
-
cloneRepository,
|
|
11
8
|
readDeployConfig,
|
|
12
|
-
pushDeployConfig
|
|
9
|
+
pushDeployConfig,
|
|
13
10
|
} from '../next/deploy.js';
|
|
14
11
|
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
updateVaultSecrets
|
|
18
|
-
} from './vault.js';
|
|
19
|
-
|
|
20
|
-
import {
|
|
21
|
-
getVaultSecretsConfigs,
|
|
22
|
-
environmentConfig
|
|
23
|
-
} from '../next/config.js';
|
|
24
|
-
import { connect } from 'http2';
|
|
25
|
-
import { promise } from 'zod';
|
|
12
|
+
import { getVaultSecrets, updateVaultSecrets } from './vault.js';
|
|
13
|
+
import { getVaultSecretsConfigs, environmentConfig } from '../next/config.js';
|
|
26
14
|
|
|
27
15
|
async function ensureDirectoryExists(dirPath) {
|
|
28
16
|
try {
|
|
@@ -33,359 +21,76 @@ async function ensureDirectoryExists(dirPath) {
|
|
|
33
21
|
}
|
|
34
22
|
}
|
|
35
23
|
|
|
36
|
-
async function
|
|
37
|
-
try {
|
|
38
|
-
await fl.mkdir(destination, { recursive: true });
|
|
39
|
-
const items = await fl.readdir(source, { withFileTypes: true });
|
|
40
|
-
|
|
41
|
-
for (const item of items) {
|
|
42
|
-
const sourcePath = path.join(source, item.name);
|
|
43
|
-
const destinationPath = path.join(destination, item.name);
|
|
44
|
-
|
|
45
|
-
if (item.isDirectory()) {
|
|
46
|
-
await copyDirectory(sourcePath, destinationPath);
|
|
47
|
-
} else {
|
|
48
|
-
await fl.copyFile(sourcePath, destinationPath);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
} catch (err) {
|
|
52
|
-
console.error(`Error copying directory: ${err.message}`);
|
|
53
|
-
throw err;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async function addApplicationToApi ({application, auth0Domain, auth0AuthToken, coreApiIdentifier}){
|
|
58
|
-
console.log("Adding application to API authorized applications...");
|
|
59
|
-
|
|
24
|
+
export async function getAuth0AuthToken(auth0Domain, clientId, clientSecret) {
|
|
60
25
|
try {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const appAuth0ClientIdData = auth0Response.data.find(client => client.name === `${application}`);
|
|
66
|
-
const appAuth0ClientId = appAuth0ClientIdData.client_id;
|
|
67
|
-
|
|
68
|
-
await axios.post(
|
|
69
|
-
`https://${auth0Domain}/api/v2/client-grants`,
|
|
26
|
+
const response = await axios.post(
|
|
27
|
+
`https://${auth0Domain}/oauth/token`,
|
|
70
28
|
{
|
|
71
|
-
client_id:
|
|
72
|
-
|
|
73
|
-
|
|
29
|
+
client_id: clientId,
|
|
30
|
+
client_secret: clientSecret,
|
|
31
|
+
audience: `https://${auth0Domain}/api/v2/`,
|
|
32
|
+
grant_type: 'client_credentials',
|
|
74
33
|
},
|
|
75
34
|
{
|
|
76
35
|
headers: {
|
|
77
|
-
|
|
78
|
-
"Content-Type": "application/json",
|
|
36
|
+
'Content-Type': 'application/json',
|
|
79
37
|
},
|
|
80
|
-
}
|
|
81
|
-
);
|
|
82
|
-
console.log(`Application (${appAuth0ClientId}) authorized for API: ${coreApiIdentifier}`);
|
|
83
|
-
} catch (err) {
|
|
84
|
-
console.error(`Failed to add application: ${application}: ${err.message}`);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async function initializeAuth0Configuration({
|
|
90
|
-
initConfiguration,
|
|
91
|
-
auth0Domain,
|
|
92
|
-
auth0AuthToken,
|
|
93
|
-
coreApiIdentifier,
|
|
94
|
-
}) {
|
|
95
|
-
if (initConfiguration === "true") {
|
|
96
|
-
try {
|
|
97
|
-
// Create a new resource server in Auth0
|
|
98
|
-
console.log("Creating resource server in Auth0...");
|
|
99
|
-
|
|
100
|
-
const resourceServerResponse = await axios.post(
|
|
101
|
-
`https://${auth0Domain}/api/v2/resource-servers`,
|
|
102
|
-
{
|
|
103
|
-
name: "docupace-core",
|
|
104
|
-
identifier: `${coreApiIdentifier}`,
|
|
105
|
-
token_lifetime: 86400,
|
|
106
|
-
allow_offline_access: false,
|
|
107
|
-
signing_alg: "RS256",
|
|
108
|
-
skip_consent_for_verifiable_first_party_clients: true,
|
|
109
|
-
scopes: [],
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
headers: {
|
|
113
|
-
Authorization: `Bearer ${auth0AuthToken}`,
|
|
114
|
-
"Content-Type": "application/json",
|
|
115
|
-
},
|
|
116
|
-
}
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
const apiId = resourceServerResponse.data.id;
|
|
120
|
-
|
|
121
|
-
// Update tenant settings with the default audience
|
|
122
|
-
console.log("Updating tenant settings...");
|
|
123
|
-
await axios.patch(
|
|
124
|
-
`https://${auth0Domain}/api/v2/tenants/settings`,
|
|
125
|
-
{
|
|
126
|
-
default_audience: `${coreApiIdentifier}`,
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
headers: {
|
|
130
|
-
Authorization: `Bearer ${auth0AuthToken}`,
|
|
131
|
-
"Content-Type": "application/json",
|
|
132
|
-
},
|
|
133
|
-
}
|
|
134
|
-
);
|
|
135
|
-
console.log("Tenant settings updated successfully.");
|
|
136
|
-
} catch (error) {
|
|
137
|
-
console.error("Error during Auth0 configuration:", error.response?.data || error.message);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async function importAuth0Templates(directoryPath, auth0Domain, auth0ClientID, auth0ClientSecret) {
|
|
143
|
-
try {
|
|
144
|
-
const config = {
|
|
145
|
-
input_file: directoryPath,
|
|
146
|
-
config: {
|
|
147
|
-
AUTH0_DOMAIN: auth0Domain,
|
|
148
|
-
AUTH0_CLIENT_ID: auth0ClientID,
|
|
149
|
-
AUTH0_CLIENT_SECRET: auth0ClientSecret,
|
|
150
38
|
},
|
|
151
|
-
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
console.log('Starting Auth0 template import...');
|
|
155
|
-
await deploy(config);
|
|
156
|
-
console.log('Auth0 template import completed successfully!');
|
|
157
|
-
} catch (error) {
|
|
158
|
-
console.error('Error during Auth0 template import:', error.message);
|
|
159
|
-
process.exit(1); // Exit with an error code
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async function updateJsonFile(filePath, updates) {
|
|
164
|
-
const content = await fs.promises.readFile(filePath, 'utf8');
|
|
165
|
-
const jsonContent = JSON.parse(content);
|
|
166
|
-
const updatedContent = JSON.stringify({...jsonContent, ...updates}, null, 2);
|
|
167
|
-
await fs.promises.writeFile(filePath, updatedContent);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async function replaceInFile(filePath, replacements) {
|
|
171
|
-
let content = await fs.promises.readFile(filePath, 'utf8');
|
|
172
|
-
|
|
173
|
-
for (const [search, replace] of replacements) {
|
|
174
|
-
const escapedSearch = search.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); // Escape special chars
|
|
175
|
-
content = content.replace(new RegExp(escapedSearch, 'g'), replace);
|
|
176
|
-
}
|
|
177
|
-
await fs.promises.writeFile(filePath, content, 'utf8');
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
async function templateAuth0(siteUrl, coreApiContext, env, filePaths, deployUI, deployGraphQLServer, commonSecrets, configureMFA) {
|
|
181
|
-
try {
|
|
182
|
-
let uiAllowedCallbacksUrls,
|
|
183
|
-
uiAllowedLogoutUrls;
|
|
184
|
-
let graphqlAllowedCallbacksUrls,
|
|
185
|
-
graphqlAllowedLogoutUrls;
|
|
186
|
-
let connectAllowedCallbacksUrls,
|
|
187
|
-
connectlAllowedLogoutUrls;
|
|
188
|
-
|
|
189
|
-
let connectClientMetadata,
|
|
190
|
-
connectCallbacks,
|
|
191
|
-
connectAddons;
|
|
192
|
-
// Configure URLs based on environment
|
|
193
|
-
if (env === 'prd') {
|
|
194
|
-
uiAllowedCallbacksUrls = [`${siteUrl}/api/auth/callback`];
|
|
195
|
-
uiAllowedLogoutUrls = [`${siteUrl}`];
|
|
196
|
-
|
|
197
|
-
graphqlAllowedCallbacksUrls = [`${siteUrl}/api/graphql/callback`];
|
|
198
|
-
graphqlAllowedLogoutUrls = [`${siteUrl}/api/graphql/`];
|
|
199
|
-
|
|
200
|
-
connectAllowedCallbacksUrls = [`${siteUrl}/connect/samlCallback?client_name=auth0`];
|
|
201
|
-
connectlAllowedLogoutUrls = [ `${siteUrl}/connect`];
|
|
202
|
-
} else {
|
|
203
|
-
uiAllowedCallbacksUrls = [
|
|
204
|
-
`${siteUrl}/api/auth/callback`,
|
|
205
|
-
`http://localhost:3000/api/auth/callback`,
|
|
206
|
-
];
|
|
207
|
-
uiAllowedLogoutUrls = [
|
|
208
|
-
`${siteUrl}`,
|
|
209
|
-
`http://localhost:3000`,
|
|
210
|
-
];
|
|
211
|
-
graphqlAllowedCallbacksUrls = [
|
|
212
|
-
`${siteUrl}/api/graphql/callback`,
|
|
213
|
-
`http://localhost:4000/api/graphql/callback`,
|
|
214
|
-
];
|
|
215
|
-
graphqlAllowedLogoutUrls = [
|
|
216
|
-
`http://localhost:4000/api/graphql/`,
|
|
217
|
-
`${siteUrl}/api/graphql/`,
|
|
218
|
-
];
|
|
219
|
-
connectAllowedCallbacksUrls = [
|
|
220
|
-
`${siteUrl}/connect/samlCallback?client_name=auth0`,
|
|
221
|
-
`http://localhost:9000/connect/samlCallback?client_name=auth0`,
|
|
222
|
-
];
|
|
223
|
-
connectlAllowedLogoutUrls = [
|
|
224
|
-
`${siteUrl}/connect`
|
|
225
|
-
];
|
|
226
|
-
|
|
227
|
-
const siteUrlNoPrefix=siteUrl.replace(/^https?:\/\//, '');
|
|
228
|
-
connectClientMetadata ={
|
|
229
|
-
"docupaceContext" : "core",
|
|
230
|
-
"docupaceHost" : `${siteUrlNoPrefix}`,
|
|
231
|
-
"docupace_context" : "core",
|
|
232
|
-
"docupace_host" : `${siteUrlNoPrefix} `
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
connectCallbacks = [
|
|
236
|
-
`${siteUrl}/connect/samlCallback?client_name=auth0`
|
|
237
|
-
];
|
|
238
|
-
|
|
239
|
-
connectAddons = {
|
|
240
|
-
"samlp": {
|
|
241
|
-
"audience": `${siteUrl}/connect`,
|
|
242
|
-
"recipient": `${siteUrl}/connect/samlCallback?client_name=auth0`,
|
|
243
|
-
"destination": `${siteUrl}/connect/samlCallback?client_name=auth0`,
|
|
244
|
-
"nameIdentifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
|
|
245
|
-
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
|
|
246
|
-
"nameIdentifierProbes": [
|
|
247
|
-
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/docupace-username"
|
|
248
|
-
],
|
|
249
|
-
"mappings": {
|
|
250
|
-
"proposalHandle": "ProposalHandle"
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const configureUI = deployUI === 'true';
|
|
259
|
-
if (configureUI) {
|
|
260
|
-
console.log('ui_allowed_callbacks_urls ->', uiAllowedCallbacksUrls);
|
|
261
|
-
console.log('ui_allowed_logout_urls ->', uiAllowedLogoutUrls);
|
|
262
|
-
|
|
263
|
-
await updateJsonFile(filePaths.uiJson, {
|
|
264
|
-
callbacks: uiAllowedCallbacksUrls,
|
|
265
|
-
allowed_logout_urls: uiAllowedLogoutUrls,
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
//TODO: move to separate function for connect
|
|
270
|
-
console.log('connect_allowed_callbacks_urls ->', connectAllowedCallbacksUrls);
|
|
271
|
-
console.log('connect_allowed_logout_urls ->', connectlAllowedLogoutUrls);
|
|
272
|
-
|
|
273
|
-
// update allowed callback url
|
|
274
|
-
await updateJsonFile(filePaths.connectJson, {
|
|
275
|
-
callbacks: connectAllowedCallbacksUrls,
|
|
276
|
-
allowed_logout_urls: connectlAllowedLogoutUrls,
|
|
277
|
-
client_metadata: connectClientMetadata,
|
|
278
|
-
addons: connectAddons
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
console.log('Updated URLs for main UI...');
|
|
284
|
-
} else {
|
|
285
|
-
await fs.promises.unlink(filePaths.uiJson);
|
|
286
|
-
await updateJsonFile(filePaths.databaseJson, {
|
|
287
|
-
enabled_clients: (content) => content.enabled_clients.filter((client) => client !== 'docupace-ui-main'),
|
|
288
|
-
});
|
|
289
|
-
console.log("Removed 'docupace-ui-main' from enabled_clients in database.json");
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const configureGraphqlServer = deployGraphQLServer === 'true';
|
|
293
|
-
if (configureGraphqlServer) {
|
|
294
|
-
console.log('graphql_allowed_callbacks_urls ->', graphqlAllowedCallbacksUrls);
|
|
295
|
-
console.log('graphql_allowed_logout_urls ->', graphqlAllowedLogoutUrls);
|
|
296
|
-
|
|
297
|
-
await updateJsonFile(filePaths.graphqlJson, {
|
|
298
|
-
callbacks: graphqlAllowedCallbacksUrls,
|
|
299
|
-
allowed_logout_urls: graphqlAllowedLogoutUrls,
|
|
300
|
-
});
|
|
301
|
-
console.log('Updated URLs for GraphQL server...');
|
|
302
|
-
} else {
|
|
303
|
-
await fs.promises.unlink(filePaths.graphqlJson);
|
|
304
|
-
await updateJsonFile(filePaths.databaseJson, {
|
|
305
|
-
enabled_clients: (content) => content.enabled_clients.filter((client) => client !== 'docupace-graphql'),
|
|
306
|
-
});
|
|
307
|
-
console.log("Removed 'docupace-graphql' from enabled_clients in database.json");
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// TWILIO configuration
|
|
311
|
-
await replaceInFile(filePaths.twilioJson, [
|
|
312
|
-
['twilioauthtokenplaceholder', commonSecrets.TWILIO_AUTH_TOKEN],
|
|
313
|
-
['twiliosidplaceholder', commonSecrets.TWILIO_SID],
|
|
314
|
-
['twiliofromplaceholder', commonSecrets.TWILIO_FROM_NUMBER],
|
|
315
|
-
]);
|
|
316
|
-
|
|
317
|
-
console.log('TWILIO configuration updated...');
|
|
318
|
-
|
|
319
|
-
const tmpSiteUrl = siteUrl.replace(/^https?:\/\//, '');
|
|
320
|
-
// Database configuration
|
|
321
|
-
await replaceInFile(filePaths.databaseLoginJs, [
|
|
322
|
-
['${docupaceHost}', tmpSiteUrl],
|
|
323
|
-
['${docupaceContext}', coreApiContext],
|
|
324
|
-
]);
|
|
325
|
-
|
|
326
|
-
console.log('MFA Template configuration started...');
|
|
327
|
-
|
|
328
|
-
try {
|
|
329
|
-
const sourceDir = configureMFA === 'DISABLED' ? 'auth0-site-setup/templateNoMFA/' : 'auth0-site-setup/templateMFA/';
|
|
330
|
-
const destinationDir = 'auth0-site-setup/template/';
|
|
331
|
-
|
|
332
|
-
console.log(`AUTH0 MFA is ${configureMFA === 'DISABLED' ? 'disabled' : 'enabled'}`);
|
|
333
|
-
await copyDirectory(sourceDir, destinationDir);
|
|
334
|
-
|
|
335
|
-
console.log('MFA configuration completed.');
|
|
336
|
-
} catch (err) {
|
|
337
|
-
console.error('Error configuring MFA:', err);
|
|
338
|
-
throw err;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
console.log('Template configuration completed.');
|
|
342
|
-
} catch (err) {
|
|
343
|
-
// console.error('Error configuring Auth0 templates:', err);
|
|
344
|
-
throw err;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
export async function getAuth0AuthToken(auth0Domain, clientId, clientSecret) {
|
|
349
|
-
try {
|
|
350
|
-
const response = await axios.post(`https://${auth0Domain}/oauth/token`, {
|
|
351
|
-
client_id: clientId,
|
|
352
|
-
client_secret: clientSecret,
|
|
353
|
-
audience: `https://${auth0Domain}/api/v2/`,
|
|
354
|
-
grant_type: 'client_credentials',
|
|
355
|
-
}, {
|
|
356
|
-
headers: {
|
|
357
|
-
'Content-Type': 'application/json',
|
|
358
|
-
},
|
|
359
|
-
});
|
|
39
|
+
);
|
|
360
40
|
|
|
361
41
|
const authToken = response.data.access_token;
|
|
362
42
|
// console.log("Auth0 Auth Token:", authToken);
|
|
363
43
|
return authToken;
|
|
364
44
|
} catch (error) {
|
|
365
|
-
console.error(
|
|
45
|
+
console.error(
|
|
46
|
+
'Error fetching Auth0 token:',
|
|
47
|
+
error.response ? error.response.data : error.message,
|
|
48
|
+
);
|
|
366
49
|
}
|
|
367
50
|
}
|
|
368
51
|
|
|
369
|
-
async function configureUI(
|
|
370
|
-
|
|
52
|
+
async function configureUI(
|
|
53
|
+
siteHost,
|
|
54
|
+
coreURL,
|
|
55
|
+
docupaceHost,
|
|
56
|
+
site,
|
|
57
|
+
env,
|
|
58
|
+
auth0Domain,
|
|
59
|
+
auth0ClientId,
|
|
60
|
+
auth0ClientSecret,
|
|
61
|
+
auth0Token,
|
|
62
|
+
vaultSiteSecretsPath,
|
|
63
|
+
imageTag,
|
|
64
|
+
repoPath,
|
|
65
|
+
) {
|
|
66
|
+
console.log(
|
|
67
|
+
`Configuring UI for site: ${site} Host: ${siteHost} in env: ${env}`,
|
|
68
|
+
);
|
|
371
69
|
siteHost = siteHost.replace('https://', '');
|
|
372
70
|
coreURL = coreURL.replace('https://', '');
|
|
373
71
|
|
|
374
|
-
|
|
375
72
|
try {
|
|
376
|
-
const auth0Response = await axios.get(
|
|
377
|
-
|
|
378
|
-
|
|
73
|
+
const auth0Response = await axios.get(
|
|
74
|
+
`https://${auth0Domain}/api/v2/clients`,
|
|
75
|
+
{
|
|
76
|
+
headers: { authorization: `Bearer ${auth0Token}` },
|
|
77
|
+
},
|
|
78
|
+
);
|
|
379
79
|
|
|
380
|
-
const uiClient = auth0Response.data.find(
|
|
80
|
+
const uiClient = auth0Response.data.find(
|
|
81
|
+
(client) => client.name === 'docupace-ui-main',
|
|
82
|
+
);
|
|
381
83
|
const uiAuth0ClientId = uiClient.client_id;
|
|
382
84
|
const uiAuth0ClientSecret = uiClient.client_secret;
|
|
383
85
|
|
|
384
86
|
// Generate Auth0 Secret
|
|
385
|
-
const uiAuth0Secret = crypto
|
|
87
|
+
const uiAuth0Secret = crypto
|
|
88
|
+
.randomBytes(48)
|
|
89
|
+
.toString('base64')
|
|
90
|
+
.replace(/[^a-zA-Z0-9]/g, '');
|
|
386
91
|
|
|
387
92
|
// Prepare data payload
|
|
388
|
-
console.log(
|
|
93
|
+
console.log('Preparing Vault UI data payload...');
|
|
389
94
|
const uiSecretData = JSON.stringify({
|
|
390
95
|
data: {
|
|
391
96
|
AUTH0_CLIENT_ID: uiAuth0ClientId,
|
|
@@ -415,6 +120,9 @@ uiMain:
|
|
|
415
120
|
env:
|
|
416
121
|
AUTH0_CLIENT_SECRET: vault:secret/data/${site}/ui/config#AUTH0_CLIENT_SECRET
|
|
417
122
|
AUTH0_SECRET: vault:secret/data/${site}/ui/config#AUTH0_SECRET
|
|
123
|
+
AWS_ACCESS_KEY_ID: vault:secret/data/${site}/aws/config#AWS_ACCESS_KEY_ID
|
|
124
|
+
AWS_BUCKET_NAME: vault:secret/data/${site}/aws/config#AWS_BUCKET_NAME
|
|
125
|
+
AWS_SECRET_ACCESS_KEY: vault:secret/data/${site}/aws/config#AWS_SECRET_ACCESS_KEY
|
|
418
126
|
image:
|
|
419
127
|
repository: registry.paperout.com/docupace-ui-main-dev-docker-local/docupace-ui-main
|
|
420
128
|
tag: ${imageTag}
|
|
@@ -438,7 +146,7 @@ ingress:
|
|
|
438
146
|
- ${siteHost}
|
|
439
147
|
secretName: dp-next-ui-cert
|
|
440
148
|
externalConnectIngress:
|
|
441
|
-
enabled:
|
|
149
|
+
enabled: true
|
|
442
150
|
className: nginx
|
|
443
151
|
annotations:
|
|
444
152
|
cert-manager.io/cluster-issuer: letsencrypt
|
|
@@ -467,57 +175,91 @@ externalConnectIngress:
|
|
|
467
175
|
- ${siteHost}
|
|
468
176
|
secretName: dp-next-ui-cert
|
|
469
177
|
externalConnectService:
|
|
470
|
-
enabled:
|
|
178
|
+
enabled: true
|
|
471
179
|
name: external-connect
|
|
472
180
|
domain: ${docupaceHost}
|
|
473
181
|
`.trim();
|
|
474
182
|
|
|
475
183
|
// Write configuration files
|
|
476
|
-
console.log(
|
|
184
|
+
console.log('Writing configuration files...');
|
|
477
185
|
await ensureDirectoryExists(path.resolve(`${repoPath}/dp/${site}`));
|
|
478
186
|
|
|
479
|
-
await fs.writeFile(
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
187
|
+
await fs.writeFile(
|
|
188
|
+
`${repoPath}/dp/${site}/ui.app.yaml`,
|
|
189
|
+
uiAppYaml,
|
|
190
|
+
(err) => {
|
|
191
|
+
if (err) {
|
|
192
|
+
console.error('Failed to write the file:', err);
|
|
193
|
+
} else {
|
|
194
|
+
console.log('File written successfully.');
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
);
|
|
486
198
|
|
|
487
|
-
await fs.writeFile(
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
199
|
+
await fs.writeFile(
|
|
200
|
+
`${repoPath}/dp/${site}/ui.values.yaml`,
|
|
201
|
+
uiValuesYaml,
|
|
202
|
+
(err) => {
|
|
203
|
+
if (err) {
|
|
204
|
+
console.error('Failed to write the file:', err);
|
|
205
|
+
} else {
|
|
206
|
+
console.log('File written successfully.');
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
);
|
|
210
|
+
console.log('Done!');
|
|
495
211
|
} catch (error) {
|
|
496
|
-
console.error(
|
|
212
|
+
console.error('Error configuring UI:', error);
|
|
497
213
|
}
|
|
498
214
|
}
|
|
499
215
|
|
|
500
|
-
async function configureGraphQLServer(
|
|
216
|
+
async function configureGraphQLServer(
|
|
217
|
+
siteHost,
|
|
218
|
+
coreURL,
|
|
219
|
+
docupaceHost,
|
|
220
|
+
site,
|
|
221
|
+
env,
|
|
222
|
+
auth0Domain,
|
|
223
|
+
auth0ClientId,
|
|
224
|
+
auth0ClientSecret,
|
|
225
|
+
auth0Token,
|
|
226
|
+
vaultSiteSecretsPath,
|
|
227
|
+
imageTag,
|
|
228
|
+
standardConfigRemoteBranch,
|
|
229
|
+
repoPath,
|
|
230
|
+
commonSecrets,
|
|
231
|
+
) {
|
|
501
232
|
siteHost = siteHost.replace('https://', '');
|
|
502
233
|
coreURL = coreURL.replace('https://', '');
|
|
503
|
-
console.log(
|
|
234
|
+
console.log(
|
|
235
|
+
`Configuring GraphQL Server for site: ${site} Host: ${siteHost} in env: ${env}`,
|
|
236
|
+
);
|
|
504
237
|
|
|
505
238
|
try {
|
|
506
|
-
const auth0Response = await axios.get(
|
|
507
|
-
|
|
508
|
-
|
|
239
|
+
const auth0Response = await axios.get(
|
|
240
|
+
`https://${auth0Domain}/api/v2/clients`,
|
|
241
|
+
{
|
|
242
|
+
headers: { authorization: `Bearer ${auth0Token}` },
|
|
243
|
+
},
|
|
244
|
+
);
|
|
509
245
|
|
|
510
|
-
const graphQLServerClient = auth0Response.data.find(
|
|
511
|
-
|
|
246
|
+
const graphQLServerClient = auth0Response.data.find(
|
|
247
|
+
(client) => client.name === 'docupace-graphql',
|
|
248
|
+
);
|
|
249
|
+
const graphQLServerClientCredentials = auth0Response.data.find(
|
|
250
|
+
(client) => client.name === 'docupace-graphql-client-credentials',
|
|
251
|
+
);
|
|
512
252
|
|
|
513
253
|
const graphQLServerAuth0ClientId = graphQLServerClient.client_id;
|
|
514
254
|
const graphQLServerAuth0ClientSecret = graphQLServerClient.client_secret;
|
|
515
255
|
|
|
516
|
-
const graphQLServerCCAuth0ClientId =
|
|
517
|
-
|
|
256
|
+
const graphQLServerCCAuth0ClientId =
|
|
257
|
+
graphQLServerClientCredentials.client_id;
|
|
258
|
+
const graphQLServerCCAuth0ClientSecret =
|
|
259
|
+
graphQLServerClientCredentials.client_secret;
|
|
518
260
|
|
|
519
261
|
// Prepare data payload
|
|
520
|
-
console.log(
|
|
262
|
+
console.log('Preparing Vault GraphQL Server data payload...');
|
|
521
263
|
const graphQLServerSecretData = JSON.stringify({
|
|
522
264
|
data: {
|
|
523
265
|
AUTH0_CLIENT_ID: graphQLServerAuth0ClientId,
|
|
@@ -580,105 +322,128 @@ ingress:
|
|
|
580
322
|
`.trim();
|
|
581
323
|
|
|
582
324
|
// Write configuration files
|
|
583
|
-
console.log(
|
|
325
|
+
console.log('Writing ArgoCD GraphQL Server configuration files...');
|
|
584
326
|
await ensureDirectoryExists(path.resolve(`${repoPath}/dp/${site}`));
|
|
585
327
|
|
|
586
|
-
await fs.writeFile(
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
328
|
+
await fs.writeFile(
|
|
329
|
+
`${repoPath}/dp/${site}/graphql-server.app.yaml`,
|
|
330
|
+
graphQLServerAppYaml,
|
|
331
|
+
(err) => {
|
|
332
|
+
if (err) {
|
|
333
|
+
console.error('Failed to write the file:', err);
|
|
334
|
+
} else {
|
|
335
|
+
console.log('File written successfully.');
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
);
|
|
593
339
|
|
|
594
|
-
await fs.writeFile(
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
340
|
+
await fs.writeFile(
|
|
341
|
+
`${repoPath}/dp/${site}/graphql-server.values.yaml`,
|
|
342
|
+
graphQLServerValuesYaml,
|
|
343
|
+
(err) => {
|
|
344
|
+
if (err) {
|
|
345
|
+
console.error('Failed to write the file:', err);
|
|
346
|
+
} else {
|
|
347
|
+
console.log('File written successfully.');
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
);
|
|
351
|
+
console.log('Done!');
|
|
602
352
|
} catch (error) {
|
|
603
|
-
console.error(
|
|
353
|
+
console.error('Error configuring GraphQL Server:', error);
|
|
604
354
|
}
|
|
605
355
|
}
|
|
606
356
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
357
|
+
export async function configureFromSite(
|
|
358
|
+
fromSite,
|
|
359
|
+
toSite,
|
|
360
|
+
fromEnv,
|
|
361
|
+
toEnv,
|
|
362
|
+
deployUI,
|
|
363
|
+
deployGraphQLServer,
|
|
364
|
+
useNewDomain,
|
|
365
|
+
) {
|
|
366
|
+
console.log(
|
|
367
|
+
`Configuring Auth0 tenants and ArgoCD apps for site: ${toSite} in env: ${toEnv} from site: ${fromSite}`,
|
|
368
|
+
);
|
|
610
369
|
// Common Secrets
|
|
611
370
|
const commonSecretsPath = getVaultSecretsConfigs(toSite).commonSecretsPath;
|
|
612
|
-
console.log(`commonSecretsPath => ${commonSecretsPath}`)
|
|
371
|
+
console.log(`commonSecretsPath => ${commonSecretsPath}`);
|
|
613
372
|
const commonSecrets = await getVaultSecrets(commonSecretsPath);
|
|
614
373
|
|
|
615
374
|
// Site Common Secrets
|
|
616
|
-
const siteCommonSecretsPath =
|
|
617
|
-
|
|
375
|
+
const siteCommonSecretsPath =
|
|
376
|
+
getVaultSecretsConfigs(toSite).siteCommonSecretsPath;
|
|
377
|
+
console.log(`siteCommonSecretsPath => ${siteCommonSecretsPath}`);
|
|
618
378
|
const siteCommonSecrets = await getVaultSecrets(siteCommonSecretsPath);
|
|
619
379
|
|
|
620
|
-
const auth0Domain = `docupace-${toEnv}-${toSite}.us.auth0.com
|
|
380
|
+
const auth0Domain = `docupace-${toEnv}-${toSite}.us.auth0.com`;
|
|
621
381
|
const auth0ClientId = siteCommonSecrets.AUTH0_CLIENT_ID;
|
|
622
382
|
const auth0ClientSecret = siteCommonSecrets.AUTH0_CLIENT_SECRET;
|
|
623
|
-
const auth0Token = await getAuth0AuthToken(
|
|
383
|
+
const auth0Token = await getAuth0AuthToken(
|
|
384
|
+
auth0Domain,
|
|
385
|
+
auth0ClientId,
|
|
386
|
+
auth0ClientSecret,
|
|
387
|
+
);
|
|
624
388
|
|
|
625
389
|
// UI app
|
|
626
390
|
const uiSecretsPath = getVaultSecretsConfigs(toSite).uiSecretsPath;
|
|
627
|
-
console.log(`uiSecretsPath => ${uiSecretsPath}`)
|
|
391
|
+
console.log(`uiSecretsPath => ${uiSecretsPath}`);
|
|
628
392
|
|
|
629
393
|
// GraphQL-Server app
|
|
630
|
-
const graphqlSecretsPath =
|
|
394
|
+
const graphqlSecretsPath =
|
|
395
|
+
getVaultSecretsConfigs(toSite).graphqlServerSecretsPath;
|
|
631
396
|
console.log(`graphqlSecretsPath => ${graphqlSecretsPath}`);
|
|
632
397
|
|
|
633
|
-
let repoPathFromEnv =
|
|
634
|
-
let repoPathToEnv =
|
|
398
|
+
let repoPathFromEnv = '';
|
|
399
|
+
let repoPathToEnv = '';
|
|
635
400
|
// Clone repositories
|
|
636
|
-
if (
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
}else {
|
|
640
|
-
|
|
641
|
-
|
|
401
|
+
if (fromEnv === toEnv) {
|
|
402
|
+
repoPathFromEnv = await cloneEnvRepository(fromEnv);
|
|
403
|
+
repoPathToEnv = repoPathFromEnv;
|
|
404
|
+
} else {
|
|
405
|
+
repoPathFromEnv = await cloneEnvRepository(fromEnv);
|
|
406
|
+
repoPathToEnv = await cloneEnvRepository(toEnv);
|
|
642
407
|
}
|
|
643
408
|
|
|
644
409
|
//TODO: clone fromEnv and toEnv. replace above with this
|
|
645
410
|
|
|
646
|
-
const auth0RepoPath = await cloneRepository('auth0-site-setup');
|
|
411
|
+
// const auth0RepoPath = await cloneRepository('auth0-site-setup');
|
|
647
412
|
|
|
648
413
|
// Read deploy configs
|
|
649
|
-
const { deployConfig: deployUIConfig } = await readDeployConfig(
|
|
414
|
+
const { deployConfig: deployUIConfig } = await readDeployConfig(
|
|
415
|
+
'ui',
|
|
416
|
+
fromEnv,
|
|
417
|
+
fromSite,
|
|
418
|
+
'values',
|
|
419
|
+
);
|
|
650
420
|
const uiImageTag = deployUIConfig.image.tag;
|
|
651
421
|
|
|
652
|
-
const { deployConfig: deployGraphQLServerConfig } = await readDeployConfig(
|
|
422
|
+
const { deployConfig: deployGraphQLServerConfig } = await readDeployConfig(
|
|
423
|
+
'graphql-server',
|
|
424
|
+
fromEnv,
|
|
425
|
+
fromSite,
|
|
426
|
+
'values',
|
|
427
|
+
);
|
|
653
428
|
const graphqlImageTag = deployGraphQLServerConfig.image.tag;
|
|
654
|
-
const graphqlStandardConfigRemoteBranch =
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
databaseJson: './auth0-site-setup/template/database-connections/docupace/database.json',
|
|
664
|
-
twilioJson: './auth0-site-setup/template/guardian/providers/sms-twilio.json',
|
|
665
|
-
};
|
|
666
|
-
|
|
667
|
-
console.log(`Copying Latest UI Image Tag: ${deployUIConfig.image.tag} from site: ${fromSite} to site: ${toSite}`);
|
|
668
|
-
console.log(`Copying Latest GraphQL Server Image Tag: ${deployGraphQLServerConfig.image.tag} from site: ${fromSite} to site: ${toSite}`);
|
|
429
|
+
const graphqlStandardConfigRemoteBranch =
|
|
430
|
+
deployGraphQLServerConfig.graphqlServer.standardConfigRemoteBranch;
|
|
431
|
+
|
|
432
|
+
console.log(
|
|
433
|
+
`Copying Latest UI Image Tag: ${deployUIConfig.image.tag} from site: ${fromSite} to site: ${toSite}`,
|
|
434
|
+
);
|
|
435
|
+
console.log(
|
|
436
|
+
`Copying Latest GraphQL Server Image Tag: ${deployGraphQLServerConfig.image.tag} from site: ${fromSite} to site: ${toSite}`,
|
|
437
|
+
);
|
|
669
438
|
|
|
670
439
|
const envConfig = environmentConfig[toEnv];
|
|
671
440
|
|
|
672
|
-
let CORE_URL,
|
|
673
|
-
SITE_HOST,
|
|
674
|
-
CORE_API_CONTEXT,
|
|
675
|
-
CONNECT_URL,
|
|
676
|
-
DOCUPACE_HOST;
|
|
441
|
+
let CORE_URL, SITE_HOST, CORE_API_CONTEXT, CONNECT_URL, DOCUPACE_HOST;
|
|
677
442
|
if (useNewDomain) {
|
|
678
443
|
const newUrl = envConfig.newUrl(toSite);
|
|
679
444
|
CORE_URL = `${newUrl}/core`;
|
|
680
445
|
SITE_HOST = newUrl;
|
|
681
|
-
CORE_API_CONTEXT =
|
|
446
|
+
CORE_API_CONTEXT = 'core';
|
|
682
447
|
CONNECT_URL = `${newUrl}/connect`;
|
|
683
448
|
DOCUPACE_HOST = envConfig.docupaceHost();
|
|
684
449
|
} else {
|
|
@@ -689,27 +454,41 @@ export async function configureFromSite(fromSite, toSite, fromEnv,toEnv, deployU
|
|
|
689
454
|
CONNECT_URL = `${oldUrl}_ui`;
|
|
690
455
|
}
|
|
691
456
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
457
|
+
if (deployUI === true || deployUI === 'true') {
|
|
458
|
+
await configureUI(
|
|
459
|
+
SITE_HOST,
|
|
460
|
+
CORE_URL,
|
|
461
|
+
DOCUPACE_HOST,
|
|
462
|
+
toSite,
|
|
463
|
+
toEnv,
|
|
464
|
+
auth0Domain,
|
|
465
|
+
auth0ClientId,
|
|
466
|
+
auth0ClientSecret,
|
|
467
|
+
auth0Token,
|
|
468
|
+
uiSecretsPath,
|
|
469
|
+
uiImageTag,
|
|
470
|
+
repoPathToEnv,
|
|
471
|
+
);
|
|
697
472
|
}
|
|
698
473
|
|
|
699
|
-
await configureGraphQLServer(
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
474
|
+
await configureGraphQLServer(
|
|
475
|
+
SITE_HOST,
|
|
476
|
+
CORE_URL,
|
|
477
|
+
DOCUPACE_HOST,
|
|
478
|
+
toSite,
|
|
479
|
+
toEnv,
|
|
480
|
+
auth0Domain,
|
|
481
|
+
auth0ClientId,
|
|
482
|
+
auth0ClientSecret,
|
|
483
|
+
auth0Token,
|
|
484
|
+
graphqlSecretsPath,
|
|
485
|
+
graphqlImageTag,
|
|
486
|
+
graphqlStandardConfigRemoteBranch,
|
|
487
|
+
repoPathToEnv,
|
|
488
|
+
commonSecrets,
|
|
489
|
+
);
|
|
490
|
+
await pushDeployConfig(
|
|
491
|
+
repoPathToEnv,
|
|
492
|
+
`Config update for ${toSite} from ${fromSite} with UI: ${uiImageTag} and GraphQL: ${graphqlImageTag}`,
|
|
493
|
+
);
|
|
715
494
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { getVaultSecrets } from './vault.js';
|
|
2
|
+
import { getVaultSecretsConfigs } from '../next/config.js';
|
|
3
|
+
import { dump } from 'auth0-deploy-cli';
|
|
4
|
+
|
|
5
|
+
export async function exportConf(site, env) {
|
|
6
|
+
try {
|
|
7
|
+
console.log(
|
|
8
|
+
`Exporting Auth0 configuration for site: ${site} and env: ${env}`,
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const siteCommonSecretsPath =
|
|
12
|
+
getVaultSecretsConfigs(site).siteCommonSecretsPath;
|
|
13
|
+
console.log(`siteCommonSecretsPath => ${siteCommonSecretsPath}`);
|
|
14
|
+
const siteCommonSecrets = await getVaultSecrets(siteCommonSecretsPath);
|
|
15
|
+
|
|
16
|
+
const auth0Domain = `docupace-${env}-${site}.us.auth0.com`;
|
|
17
|
+
const auth0ClientId = siteCommonSecrets.AUTH0_CLIENT_ID;
|
|
18
|
+
const auth0ClientSecret = siteCommonSecrets.AUTH0_CLIENT_SECRET;
|
|
19
|
+
|
|
20
|
+
const config = {
|
|
21
|
+
config: {
|
|
22
|
+
AUTH0_DOMAIN: auth0Domain,
|
|
23
|
+
AUTH0_CLIENT_ID: auth0ClientId,
|
|
24
|
+
AUTH0_CLIENT_SECRET: auth0ClientSecret,
|
|
25
|
+
},
|
|
26
|
+
format: 'directory',
|
|
27
|
+
output_folder: `./auth0-${site}-export`,
|
|
28
|
+
export_ids: false,
|
|
29
|
+
env: false,
|
|
30
|
+
debug: true,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
console.log(`Starting Auth0 ${site} configuration export...`);
|
|
34
|
+
await dump(config);
|
|
35
|
+
console.log(`Auth0 ${site} configuration export completed successfully!`);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error(
|
|
38
|
+
`Error during Auth0 ${site} configuration export:`,
|
|
39
|
+
error.message,
|
|
40
|
+
);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { cloneRepository } from '../next/deploy.js';
|
|
5
|
+
import { getAuth0AuthToken } from './configure.js';
|
|
6
|
+
import { getVaultSecrets } from './vault.js';
|
|
7
|
+
import { getVaultSecretsConfigs } from '../next/config.js';
|
|
8
|
+
import { pushDeployConfig } from '../next/deploy.js';
|
|
9
|
+
|
|
10
|
+
export async function getAuth0Metadata(site, env) {
|
|
11
|
+
try {
|
|
12
|
+
const connectDeployRepoPath = await cloneRepository('connect-deploy');
|
|
13
|
+
|
|
14
|
+
process.chdir(`${connectDeployRepoPath}/envs/${env}/${site}`);
|
|
15
|
+
const configPath = path.join('conf', 'application.conf');
|
|
16
|
+
const appConf = await fs.readFile(configPath, 'utf-8');
|
|
17
|
+
const connectContext = appConf.match(
|
|
18
|
+
/application\.context\s*=\s*"(.*?)"/,
|
|
19
|
+
)?.[1];
|
|
20
|
+
|
|
21
|
+
if (!connectContext) {
|
|
22
|
+
console.error('connectContext not found in application.conf. Exiting...');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const siteHost = appConf.match(
|
|
27
|
+
/docupace\.baseUrlClient\s*=\s*"?https?:\/\/([^/]+)"?/,
|
|
28
|
+
)?.[1];
|
|
29
|
+
|
|
30
|
+
if (!siteHost) {
|
|
31
|
+
console.error('siteHost not found in application.conf. Exiting...');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const connectEndpoint = `https://${siteHost}${connectContext}`;
|
|
36
|
+
console.log('CONNECT_ENDPOINT:', connectEndpoint);
|
|
37
|
+
|
|
38
|
+
console.log('Requesting token from Auth0...');
|
|
39
|
+
const siteCommonSecretsPath =
|
|
40
|
+
getVaultSecretsConfigs(site).siteCommonSecretsPath;
|
|
41
|
+
console.log(`siteCommonSecretsPath => ${siteCommonSecretsPath}`);
|
|
42
|
+
const siteCommonSecrets = await getVaultSecrets(siteCommonSecretsPath);
|
|
43
|
+
const auth0Domain = `docupace-${env}-${site}.us.auth0.com`;
|
|
44
|
+
const auth0ClientId = siteCommonSecrets.AUTH0_CLIENT_ID;
|
|
45
|
+
const auth0ClientSecret = siteCommonSecrets.AUTH0_CLIENT_SECRET;
|
|
46
|
+
const auth0Token = await getAuth0AuthToken(
|
|
47
|
+
auth0Domain,
|
|
48
|
+
auth0ClientId,
|
|
49
|
+
auth0ClientSecret,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const auth0Response = await axios.get(
|
|
53
|
+
`https://${auth0Domain}/api/v2/clients`,
|
|
54
|
+
{
|
|
55
|
+
headers: { authorization: `Bearer ${auth0Token}` },
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const connectClient = auth0Response.data.find(
|
|
60
|
+
(client) => client.name === 'docupace-connect',
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (!connectClient) {
|
|
64
|
+
console.error('Client "docupace-connect" not found.');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const clientId = connectClient.client_id;
|
|
69
|
+
console.log('Found client_id:', clientId);
|
|
70
|
+
|
|
71
|
+
const metadataRes = await axios.get(
|
|
72
|
+
`https://${auth0Domain}/samlp/metadata/${clientId}`,
|
|
73
|
+
{
|
|
74
|
+
responseType: 'text',
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const metadata = metadataRes.data;
|
|
79
|
+
|
|
80
|
+
if (metadata.length < 2000) {
|
|
81
|
+
console.error(
|
|
82
|
+
'Downloaded metadata looks incorrect (too small). Exiting...',
|
|
83
|
+
);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
await fs.ensureDir('conf/saml');
|
|
87
|
+
await fs.writeFile('conf/saml/auth0.xml', metadata);
|
|
88
|
+
console.log('SAML metadata written to conf/saml/auth0.xml');
|
|
89
|
+
|
|
90
|
+
let newConfig = appConf;
|
|
91
|
+
|
|
92
|
+
if (/useSAML\s*=/.test(appConf)) {
|
|
93
|
+
newConfig = newConfig.replace(/useSAML\s*=.*/, 'useSAML=true');
|
|
94
|
+
} else {
|
|
95
|
+
newConfig += '\nuseSAML=true';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const replacements = {
|
|
99
|
+
'saml.clients.auth0.idpMetadataPath': '${samlEnvPath}"/auth0.xml"',
|
|
100
|
+
'saml.clients.auth0.spEntityId': `"${connectEndpoint}"`,
|
|
101
|
+
'saml.clients.auth0.redirectFormInput': '"RelayState"',
|
|
102
|
+
'saml.clients.auth0.idpLoginUrl': `"https://${auth0Domain}/v2/logout?client_id=${clientId}&returnTo=${connectEndpoint}"`,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
for (const [key, value] of Object.entries(replacements)) {
|
|
106
|
+
const pattern = new RegExp(`${key}\\s*=.*`, 'g');
|
|
107
|
+
if (pattern.test(newConfig)) {
|
|
108
|
+
newConfig = newConfig.replace(pattern, `${key}=${value}`);
|
|
109
|
+
} else {
|
|
110
|
+
newConfig += `\n${key}=${value}`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
await fs.writeFile(configPath, newConfig);
|
|
115
|
+
console.log('The application.conf has been updated.');
|
|
116
|
+
await pushDeployConfig(
|
|
117
|
+
connectDeployRepoPath,
|
|
118
|
+
`Auth0 SAML metadata update for site: (${site}) in env: (${env})`,
|
|
119
|
+
);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error('Error:', error.message);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
}
|
package/src/auth0/vault.js
CHANGED
|
@@ -44,7 +44,7 @@ export async function getVaultSecrets(vaultPath) {
|
|
|
44
44
|
} catch (error) {
|
|
45
45
|
if (error.response) {
|
|
46
46
|
console.error(
|
|
47
|
-
`Error: Failed to connect to Vault server at ${vaultAddr}. Response: ${error.response.status} ${error.response.statusText}
|
|
47
|
+
`Error: Failed to connect to Vault server at ${vaultAddr}. Response: ${error.response.status} ${error.response.statusText}`,
|
|
48
48
|
);
|
|
49
49
|
} else {
|
|
50
50
|
console.error(`Error: ${error.message}`);
|
|
@@ -88,7 +88,7 @@ export async function updateVaultSecrets(vaultPath, secretData) {
|
|
|
88
88
|
'X-Vault-Token': vaultToken,
|
|
89
89
|
'Content-Type': 'application/json',
|
|
90
90
|
},
|
|
91
|
-
}
|
|
91
|
+
},
|
|
92
92
|
);
|
|
93
93
|
|
|
94
94
|
// Return the response from Vault
|
|
@@ -97,7 +97,7 @@ export async function updateVaultSecrets(vaultPath, secretData) {
|
|
|
97
97
|
} catch (error) {
|
|
98
98
|
if (error.response) {
|
|
99
99
|
console.error(
|
|
100
|
-
`Error: Failed to update secret at ${vaultPath}. Response: ${error.response.status} ${error.response.statusText}
|
|
100
|
+
`Error: Failed to update secret at ${vaultPath}. Response: ${error.response.status} ${error.response.statusText}`,
|
|
101
101
|
);
|
|
102
102
|
} else {
|
|
103
103
|
console.error(`Error: ${error.message}`);
|
package/terraform/init.sh
CHANGED
|
@@ -33,16 +33,28 @@ echo "$atlassian_workspace_runner_ssh_key" | base64 -d > ~/.ssh/id_ed25519
|
|
|
33
33
|
chmod 600 ~/.ssh/id_ed25519
|
|
34
34
|
ssh-keyscan bitbucket.org > ~/.ssh/known_hosts
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
info () {
|
|
37
|
+
echo "PROJECT => $PROJECT"
|
|
38
|
+
echo "CURRENT_ENVIRONMENT => $CURRENT_ENVIRONMENT"
|
|
39
|
+
echo "SITE_NAME => $SITE_NAME"
|
|
40
|
+
}
|
|
37
41
|
|
|
38
42
|
if [[ "$PROJECT" == "s3" ]]; then
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
info
|
|
44
|
+
terraform init \
|
|
45
|
+
-input=false \
|
|
46
|
+
-reconfigure \
|
|
47
|
+
-backend=true \
|
|
48
|
+
-backend-config=./env/${CURRENT_ENVIRONMENT}/us-west-2/backend.tfvars \
|
|
49
|
+
-backend-config="key=us-west-2/${PROJECT}/${SITE_NAME}/${CURRENT_ENVIRONMENT}/terraform.tfstate"
|
|
50
|
+
elif [[ "$PROJECT" == "idp" ]]; then
|
|
51
|
+
info
|
|
52
|
+
terraform init \
|
|
53
|
+
-input=false \
|
|
54
|
+
-reconfigure \
|
|
55
|
+
-backend=true \
|
|
56
|
+
-backend-config=./env/${CURRENT_ENVIRONMENT}/us-west-2/backend.tfvars \
|
|
57
|
+
-backend-config="key=us-west-2/${PROJECT}/${SITE_NAME}/${CURRENT_ENVIRONMENT}/terraform.tfstate"
|
|
46
58
|
else
|
|
47
59
|
terraform init -backend-config=./env/${CURRENT_ENVIRONMENT}/us-west-2/backend.tfvars --reconfigure
|
|
48
|
-
fi
|
|
60
|
+
fi
|
package/terraform/plan.sh
CHANGED
|
@@ -44,11 +44,18 @@ elif [[ "$PROJECT" == "s3" ]];then
|
|
|
44
44
|
-var="site=${SITE_NAME}" \
|
|
45
45
|
-var="env=${CURRENT_ENVIRONMENT}" \
|
|
46
46
|
-out .tfplan
|
|
47
|
+
elif [[ "$PROJECT" == "idp" ]];then
|
|
48
|
+
terraform plan -var-file="./env/${CURRENT_ENVIRONMENT}/us-west-2/terraform.tfvars" \
|
|
49
|
+
-var="site=${SITE_NAME}" \
|
|
50
|
+
-var="env=${CURRENT_ENVIRONMENT}" \
|
|
51
|
+
-var="docupace_domain=${DOCUPACE_DOMAIN}" \
|
|
52
|
+
-var="docupace_next_domain=${DOCUPACE_NEXT_DOMAIN}" \
|
|
53
|
+
-var="old_page_design=${USE_OLD_PAGE_DESIGN}" \
|
|
54
|
+
-var="use_new_domain=${USE_NEW_DOMAIN}" \
|
|
55
|
+
-var="configure_autologin=${CONFIGURE_AUTOLOGIN}" \
|
|
56
|
+
-var="configure_ui_main=${CONFIGURE_UI_MAIN}" \
|
|
57
|
+
-var="enable_mfa=${ENABLE_MFA}" \
|
|
58
|
+
-out .tfplan
|
|
47
59
|
else
|
|
48
60
|
terraform plan -var-file="./env/${CURRENT_ENVIRONMENT}/us-west-2/terraform.tfvars" -out .tfplan
|
|
49
61
|
fi
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|