indraq_cli 2.1.0 → 2.2.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/LICENSE +21 -21
- package/README.md +41 -15
- package/cloud-api/.dockerignore +18 -18
- package/cloud-api/.env.example +14 -14
- package/cloud-api/Dockerfile +19 -19
- package/cloud-api/README.md +93 -93
- package/cloud-api/dist/index.js +265 -27
- package/cloud-api/node_modules/.package-lock.json +1 -1
- package/cloud-api/package-lock.json +2 -2
- package/cloud-api/package.json +1 -1
- package/cloud-api/sql/001_init.sql +8 -8
- package/cloud-api/sql/002_user_providers_and_project_resources.sql +40 -40
- package/cloud-api/sql/003_environment_infrastructure.sql +19 -19
- package/cloud-api/sql/004_managed_aws_credentials.sql +20 -20
- package/cloud-api/sql/005_project_members_and_resource_grants.sql +22 -22
- package/cloud-api/sql/006_catalog_identity_password_security.sql +96 -96
- package/cloud-api/sql/007_aws_access_key_rotation.sql +16 -16
- package/cloud-api/sql/008_provider_scopes.sql +91 -91
- package/cloud-api/sql/009_scope_user_secrets_and_project_lifecycle.sql +13 -0
- package/cloud-api/src/index.ts +164 -27
- package/cloud-api/tsconfig.json +18 -18
- package/dist/cli/help-content.d.ts.map +1 -1
- package/dist/cli/help-content.js +29 -7
- package/dist/cli/help-content.js.map +1 -1
- package/dist/modules/access/commands/access.command.js +30 -30
- package/dist/modules/aws/services/route53-lookup.service.js.map +1 -1
- package/dist/modules/cloud/commands/cloud.command.d.ts +4 -0
- package/dist/modules/cloud/commands/cloud.command.d.ts.map +1 -1
- package/dist/modules/cloud/commands/cloud.command.js +52 -1
- package/dist/modules/cloud/commands/cloud.command.js.map +1 -1
- package/dist/modules/cloud/index.d.ts.map +1 -1
- package/dist/modules/cloud/index.js +6 -3
- package/dist/modules/cloud/index.js.map +1 -1
- package/dist/modules/cloud/services/cloud-jenkins.service.js +71 -71
- package/dist/modules/cloud/services/user-provider.service.d.ts +2 -8
- package/dist/modules/cloud/services/user-provider.service.d.ts.map +1 -1
- package/dist/modules/cloud/services/user-provider.service.js +7 -35
- package/dist/modules/cloud/services/user-provider.service.js.map +1 -1
- package/dist/modules/deploy/commands/build.command.d.ts +1 -0
- package/dist/modules/deploy/commands/build.command.d.ts.map +1 -1
- package/dist/modules/deploy/commands/build.command.js +12 -5
- package/dist/modules/deploy/commands/build.command.js.map +1 -1
- package/dist/modules/deploy/index.d.ts.map +1 -1
- package/dist/modules/deploy/index.js +11 -4
- package/dist/modules/deploy/index.js.map +1 -1
- package/dist/modules/prebuild/commands/prebuild.command.d.ts +0 -4
- package/dist/modules/prebuild/commands/prebuild.command.d.ts.map +1 -1
- package/dist/modules/prebuild/commands/prebuild.command.js +34 -38
- package/dist/modules/prebuild/commands/prebuild.command.js.map +1 -1
- package/dist/modules/prebuild/index.d.ts.map +1 -1
- package/dist/modules/prebuild/index.js +4 -8
- package/dist/modules/prebuild/index.js.map +1 -1
- package/dist/modules/scaffold/services/docker-template.service.js +95 -95
- package/dist/modules/scopes/commands/scope.command.d.ts.map +1 -1
- package/dist/modules/scopes/commands/scope.command.js +3 -47
- package/dist/modules/scopes/commands/scope.command.js.map +1 -1
- package/dist/modules/scopes/services/scope-native.service.js +2 -2
- package/dist/modules/scopes/services/scope-native.service.js.map +1 -1
- package/dist/modules/users/commands/user.command.d.ts +1 -0
- package/dist/modules/users/commands/user.command.d.ts.map +1 -1
- package/dist/modules/users/commands/user.command.js +15 -1
- package/dist/modules/users/commands/user.command.js.map +1 -1
- package/dist/modules/users/index.d.ts.map +1 -1
- package/dist/modules/users/index.js +3 -2
- package/dist/modules/users/index.js.map +1 -1
- package/dist/modules/users/providers/jenkins-user.provider.js +95 -95
- package/dist/shared/config/config-files.js +7 -7
- package/dist/shared/jenkins/jenkins.service.d.ts.map +1 -1
- package/dist/shared/jenkins/jenkins.service.js +13 -8
- package/dist/shared/jenkins/jenkins.service.js.map +1 -1
- package/dist/shared/jenkins/role-strategy-groovy.js +84 -84
- package/docs/ARCHITECTURE.md +29 -29
- package/docs/CREATE-DEPLOYMENT-reference.groovy +1105 -1105
- package/package.json +9 -5
- package/templates/jenkins/CREATE-DEPLOYMENT.groovy +1105 -1105
- package/templates/jenkins/Jenkinsfile-Mobile-App +759 -759
- package/CHANGELOG_v2.1.0.md +0 -27
- package/UPGRADE_v2.0_to_v2.1.md +0 -68
- package/cloud-api/dist/index.js.map +0 -1
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
-- managed AWS IAM credentials.
|
|
2
|
-
-- AWS only returns SecretAccessKey when an access key is created. IndraQ stores
|
|
3
|
-
-- the generated secret encrypted in Cloud so the owning IndraQ user can resolve
|
|
4
|
-
-- it later without relying on AWS to recover it.
|
|
5
|
-
CREATE TABLE IF NOT EXISTS managed_aws_credentials (
|
|
6
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
-
cloud_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
8
|
-
aws_username text NOT NULL,
|
|
9
|
-
access_key_id text NOT NULL,
|
|
10
|
-
encrypted_secret_access_key text NOT NULL,
|
|
11
|
-
indraq_role text NOT NULL CHECK (indraq_role IN ('user','manager','admin')),
|
|
12
|
-
created_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
13
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
14
|
-
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
15
|
-
UNIQUE(cloud_user_id, aws_username),
|
|
16
|
-
UNIQUE(access_key_id)
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
CREATE INDEX IF NOT EXISTS managed_aws_credentials_user_idx
|
|
20
|
-
ON managed_aws_credentials(cloud_user_id, aws_username);
|
|
1
|
+
-- managed AWS IAM credentials.
|
|
2
|
+
-- AWS only returns SecretAccessKey when an access key is created. IndraQ stores
|
|
3
|
+
-- the generated secret encrypted in Cloud so the owning IndraQ user can resolve
|
|
4
|
+
-- it later without relying on AWS to recover it.
|
|
5
|
+
CREATE TABLE IF NOT EXISTS managed_aws_credentials (
|
|
6
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
+
cloud_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
8
|
+
aws_username text NOT NULL,
|
|
9
|
+
access_key_id text NOT NULL,
|
|
10
|
+
encrypted_secret_access_key text NOT NULL,
|
|
11
|
+
indraq_role text NOT NULL CHECK (indraq_role IN ('user','manager','admin')),
|
|
12
|
+
created_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
13
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
14
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
15
|
+
UNIQUE(cloud_user_id, aws_username),
|
|
16
|
+
UNIQUE(access_key_id)
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
CREATE INDEX IF NOT EXISTS managed_aws_credentials_user_idx
|
|
20
|
+
ON managed_aws_credentials(cloud_user_id, aws_username);
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
-- Project membership and per-resource access grants.
|
|
2
|
-
-- Project membership lets a user work with a project; resource grants control
|
|
3
|
-
-- which provider resources a normal user can read/update. Managers/admins can
|
|
4
|
-
-- manage membership and grants with audited reasons.
|
|
5
|
-
ALTER TABLE project_members
|
|
6
|
-
ADD COLUMN IF NOT EXISTS added_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
7
|
-
ADD COLUMN IF NOT EXISTS added_at timestamptz NOT NULL DEFAULT now();
|
|
8
|
-
|
|
9
|
-
CREATE TABLE IF NOT EXISTS project_resource_grants (
|
|
10
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
11
|
-
project_resource_id uuid NOT NULL REFERENCES project_resources(id) ON DELETE CASCADE,
|
|
12
|
-
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
13
|
-
permission text NOT NULL DEFAULT 'manage' CHECK (permission IN ('view','manage')),
|
|
14
|
-
created_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
15
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
16
|
-
UNIQUE(project_resource_id, user_id)
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
CREATE INDEX IF NOT EXISTS project_resource_grants_user_idx
|
|
20
|
-
ON project_resource_grants(user_id, project_resource_id);
|
|
21
|
-
CREATE INDEX IF NOT EXISTS project_resource_grants_resource_idx
|
|
22
|
-
ON project_resource_grants(project_resource_id, user_id);
|
|
1
|
+
-- Project membership and per-resource access grants.
|
|
2
|
+
-- Project membership lets a user work with a project; resource grants control
|
|
3
|
+
-- which provider resources a normal user can read/update. Managers/admins can
|
|
4
|
+
-- manage membership and grants with audited reasons.
|
|
5
|
+
ALTER TABLE project_members
|
|
6
|
+
ADD COLUMN IF NOT EXISTS added_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
7
|
+
ADD COLUMN IF NOT EXISTS added_at timestamptz NOT NULL DEFAULT now();
|
|
8
|
+
|
|
9
|
+
CREATE TABLE IF NOT EXISTS project_resource_grants (
|
|
10
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
11
|
+
project_resource_id uuid NOT NULL REFERENCES project_resources(id) ON DELETE CASCADE,
|
|
12
|
+
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
13
|
+
permission text NOT NULL DEFAULT 'manage' CHECK (permission IN ('view','manage')),
|
|
14
|
+
created_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
15
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
16
|
+
UNIQUE(project_resource_id, user_id)
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
CREATE INDEX IF NOT EXISTS project_resource_grants_user_idx
|
|
20
|
+
ON project_resource_grants(user_id, project_resource_id);
|
|
21
|
+
CREATE INDEX IF NOT EXISTS project_resource_grants_resource_idx
|
|
22
|
+
ON project_resource_grants(project_resource_id, user_id);
|
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
-- Organization-wide catalog constraints, project access levels, first-login
|
|
2
|
-
-- password changes, self-service OTP resets, and managed external identities.
|
|
3
|
-
|
|
4
|
-
ALTER TABLE users
|
|
5
|
-
ADD COLUMN IF NOT EXISTS must_change_password boolean NOT NULL DEFAULT false,
|
|
6
|
-
ADD COLUMN IF NOT EXISTS password_changed_at timestamptz,
|
|
7
|
-
ADD COLUMN IF NOT EXISTS last_login_at timestamptz;
|
|
8
|
-
|
|
9
|
-
ALTER TABLE project_members
|
|
10
|
-
ADD COLUMN IF NOT EXISTS access_level text NOT NULL DEFAULT 'write';
|
|
11
|
-
|
|
12
|
-
DO $$
|
|
13
|
-
BEGIN
|
|
14
|
-
IF NOT EXISTS (
|
|
15
|
-
SELECT 1 FROM pg_constraint WHERE conname = 'project_members_access_level_check'
|
|
16
|
-
) THEN
|
|
17
|
-
ALTER TABLE project_members
|
|
18
|
-
ADD CONSTRAINT project_members_access_level_check
|
|
19
|
-
CHECK (access_level IN ('view','write'));
|
|
20
|
-
END IF;
|
|
21
|
-
END $$;
|
|
22
|
-
|
|
23
|
-
UPDATE project_members SET access_level='write' WHERE role='owner';
|
|
24
|
-
|
|
25
|
-
-- Resolve historical duplicate project names before enforcing organization-wide
|
|
26
|
-
-- case-insensitive uniqueness. The oldest row keeps the original display name.
|
|
27
|
-
WITH ranked AS (
|
|
28
|
-
SELECT id, name,
|
|
29
|
-
row_number() OVER (PARTITION BY lower(name) ORDER BY created_at, id) AS rn
|
|
30
|
-
FROM projects
|
|
31
|
-
)
|
|
32
|
-
UPDATE projects p
|
|
33
|
-
SET name = p.name || '-legacy-' || left(p.id::text, 8), updated_at=now()
|
|
34
|
-
FROM ranked r
|
|
35
|
-
WHERE p.id=r.id AND r.rn > 1;
|
|
36
|
-
|
|
37
|
-
CREATE UNIQUE INDEX IF NOT EXISTS projects_name_lower_unique_idx
|
|
38
|
-
ON projects (lower(name));
|
|
39
|
-
|
|
40
|
-
-- GHCR image names are organization-wide claims. Resolve historical duplicate
|
|
41
|
-
-- DB claims before adding the unique index; this does not mutate any registry.
|
|
42
|
-
WITH ranked AS (
|
|
43
|
-
SELECT id,
|
|
44
|
-
row_number() OVER (
|
|
45
|
-
PARTITION BY lower(config->>'fullImage')
|
|
46
|
-
ORDER BY created_at, id
|
|
47
|
-
) AS rn
|
|
48
|
-
FROM project_resources
|
|
49
|
-
WHERE provider='ghcr'
|
|
50
|
-
AND config ? 'fullImage'
|
|
51
|
-
AND coalesce(config->>'fullImage','') <> ''
|
|
52
|
-
)
|
|
53
|
-
UPDATE project_resources pr
|
|
54
|
-
SET config = jsonb_set(
|
|
55
|
-
jsonb_set(pr.config, '{fullImage}', to_jsonb((pr.config->>'fullImage') || '-legacy-' || left(pr.id::text,8)), true),
|
|
56
|
-
'{imageName}', to_jsonb(coalesce(pr.config->>'imageName','image') || '-legacy-' || left(pr.id::text,8)), true
|
|
57
|
-
),
|
|
58
|
-
updated_at=now()
|
|
59
|
-
FROM ranked r
|
|
60
|
-
WHERE pr.id=r.id AND r.rn > 1;
|
|
61
|
-
|
|
62
|
-
CREATE UNIQUE INDEX IF NOT EXISTS project_resources_ghcr_full_image_unique_idx
|
|
63
|
-
ON project_resources ((lower(config->>'fullImage')))
|
|
64
|
-
WHERE provider='ghcr'
|
|
65
|
-
AND config ? 'fullImage'
|
|
66
|
-
AND coalesce(config->>'fullImage','') <> '';
|
|
67
|
-
|
|
68
|
-
CREATE TABLE IF NOT EXISTS managed_external_accounts (
|
|
69
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
70
|
-
cloud_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
71
|
-
provider text NOT NULL CHECK (provider IN ('npm','jenkins-dev','jenkins-prod')),
|
|
72
|
-
external_username text NOT NULL,
|
|
73
|
-
external_email text,
|
|
74
|
-
managed_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
75
|
-
config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
76
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
77
|
-
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
78
|
-
UNIQUE(cloud_user_id, provider)
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
CREATE INDEX IF NOT EXISTS managed_external_accounts_manager_idx
|
|
82
|
-
ON managed_external_accounts(managed_by_user_id, provider);
|
|
83
|
-
|
|
84
|
-
CREATE TABLE IF NOT EXISTS password_reset_otps (
|
|
85
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
86
|
-
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
87
|
-
otp_hash text NOT NULL,
|
|
88
|
-
expires_at timestamptz NOT NULL,
|
|
89
|
-
attempts integer NOT NULL DEFAULT 0,
|
|
90
|
-
max_attempts integer NOT NULL DEFAULT 5,
|
|
91
|
-
used_at timestamptz,
|
|
92
|
-
created_at timestamptz NOT NULL DEFAULT now()
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
CREATE INDEX IF NOT EXISTS password_reset_otps_user_idx
|
|
96
|
-
ON password_reset_otps(user_id, created_at DESC);
|
|
1
|
+
-- Organization-wide catalog constraints, project access levels, first-login
|
|
2
|
+
-- password changes, self-service OTP resets, and managed external identities.
|
|
3
|
+
|
|
4
|
+
ALTER TABLE users
|
|
5
|
+
ADD COLUMN IF NOT EXISTS must_change_password boolean NOT NULL DEFAULT false,
|
|
6
|
+
ADD COLUMN IF NOT EXISTS password_changed_at timestamptz,
|
|
7
|
+
ADD COLUMN IF NOT EXISTS last_login_at timestamptz;
|
|
8
|
+
|
|
9
|
+
ALTER TABLE project_members
|
|
10
|
+
ADD COLUMN IF NOT EXISTS access_level text NOT NULL DEFAULT 'write';
|
|
11
|
+
|
|
12
|
+
DO $$
|
|
13
|
+
BEGIN
|
|
14
|
+
IF NOT EXISTS (
|
|
15
|
+
SELECT 1 FROM pg_constraint WHERE conname = 'project_members_access_level_check'
|
|
16
|
+
) THEN
|
|
17
|
+
ALTER TABLE project_members
|
|
18
|
+
ADD CONSTRAINT project_members_access_level_check
|
|
19
|
+
CHECK (access_level IN ('view','write'));
|
|
20
|
+
END IF;
|
|
21
|
+
END $$;
|
|
22
|
+
|
|
23
|
+
UPDATE project_members SET access_level='write' WHERE role='owner';
|
|
24
|
+
|
|
25
|
+
-- Resolve historical duplicate project names before enforcing organization-wide
|
|
26
|
+
-- case-insensitive uniqueness. The oldest row keeps the original display name.
|
|
27
|
+
WITH ranked AS (
|
|
28
|
+
SELECT id, name,
|
|
29
|
+
row_number() OVER (PARTITION BY lower(name) ORDER BY created_at, id) AS rn
|
|
30
|
+
FROM projects
|
|
31
|
+
)
|
|
32
|
+
UPDATE projects p
|
|
33
|
+
SET name = p.name || '-legacy-' || left(p.id::text, 8), updated_at=now()
|
|
34
|
+
FROM ranked r
|
|
35
|
+
WHERE p.id=r.id AND r.rn > 1;
|
|
36
|
+
|
|
37
|
+
CREATE UNIQUE INDEX IF NOT EXISTS projects_name_lower_unique_idx
|
|
38
|
+
ON projects (lower(name));
|
|
39
|
+
|
|
40
|
+
-- GHCR image names are organization-wide claims. Resolve historical duplicate
|
|
41
|
+
-- DB claims before adding the unique index; this does not mutate any registry.
|
|
42
|
+
WITH ranked AS (
|
|
43
|
+
SELECT id,
|
|
44
|
+
row_number() OVER (
|
|
45
|
+
PARTITION BY lower(config->>'fullImage')
|
|
46
|
+
ORDER BY created_at, id
|
|
47
|
+
) AS rn
|
|
48
|
+
FROM project_resources
|
|
49
|
+
WHERE provider='ghcr'
|
|
50
|
+
AND config ? 'fullImage'
|
|
51
|
+
AND coalesce(config->>'fullImage','') <> ''
|
|
52
|
+
)
|
|
53
|
+
UPDATE project_resources pr
|
|
54
|
+
SET config = jsonb_set(
|
|
55
|
+
jsonb_set(pr.config, '{fullImage}', to_jsonb((pr.config->>'fullImage') || '-legacy-' || left(pr.id::text,8)), true),
|
|
56
|
+
'{imageName}', to_jsonb(coalesce(pr.config->>'imageName','image') || '-legacy-' || left(pr.id::text,8)), true
|
|
57
|
+
),
|
|
58
|
+
updated_at=now()
|
|
59
|
+
FROM ranked r
|
|
60
|
+
WHERE pr.id=r.id AND r.rn > 1;
|
|
61
|
+
|
|
62
|
+
CREATE UNIQUE INDEX IF NOT EXISTS project_resources_ghcr_full_image_unique_idx
|
|
63
|
+
ON project_resources ((lower(config->>'fullImage')))
|
|
64
|
+
WHERE provider='ghcr'
|
|
65
|
+
AND config ? 'fullImage'
|
|
66
|
+
AND coalesce(config->>'fullImage','') <> '';
|
|
67
|
+
|
|
68
|
+
CREATE TABLE IF NOT EXISTS managed_external_accounts (
|
|
69
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
70
|
+
cloud_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
71
|
+
provider text NOT NULL CHECK (provider IN ('npm','jenkins-dev','jenkins-prod')),
|
|
72
|
+
external_username text NOT NULL,
|
|
73
|
+
external_email text,
|
|
74
|
+
managed_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
75
|
+
config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
76
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
77
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
78
|
+
UNIQUE(cloud_user_id, provider)
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
CREATE INDEX IF NOT EXISTS managed_external_accounts_manager_idx
|
|
82
|
+
ON managed_external_accounts(managed_by_user_id, provider);
|
|
83
|
+
|
|
84
|
+
CREATE TABLE IF NOT EXISTS password_reset_otps (
|
|
85
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
86
|
+
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
87
|
+
otp_hash text NOT NULL,
|
|
88
|
+
expires_at timestamptz NOT NULL,
|
|
89
|
+
attempts integer NOT NULL DEFAULT 0,
|
|
90
|
+
max_attempts integer NOT NULL DEFAULT 5,
|
|
91
|
+
used_at timestamptz,
|
|
92
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
CREATE INDEX IF NOT EXISTS password_reset_otps_user_idx
|
|
96
|
+
ON password_reset_otps(user_id, created_at DESC);
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
-- AWS access-key rotation ownership.
|
|
2
|
-
-- The manager/admin provider that manages an IAM user's key is tracked so a
|
|
3
|
-
-- normal user can request self-service rotation without receiving broad IAM
|
|
4
|
-
-- permissions. Managers/admins can rotate keys for users they are allowed to
|
|
5
|
-
-- manage. Secret access keys remain encrypted at rest in IndraQ Cloud.
|
|
6
|
-
|
|
7
|
-
ALTER TABLE managed_aws_credentials
|
|
8
|
-
ADD COLUMN IF NOT EXISTS managed_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL;
|
|
9
|
-
|
|
10
|
-
UPDATE managed_aws_credentials
|
|
11
|
-
SET managed_by_user_id = created_by
|
|
12
|
-
WHERE managed_by_user_id IS NULL
|
|
13
|
-
AND created_by IS NOT NULL;
|
|
14
|
-
|
|
15
|
-
CREATE INDEX IF NOT EXISTS managed_aws_credentials_manager_idx
|
|
16
|
-
ON managed_aws_credentials(managed_by_user_id, cloud_user_id);
|
|
1
|
+
-- AWS access-key rotation ownership.
|
|
2
|
+
-- The manager/admin provider that manages an IAM user's key is tracked so a
|
|
3
|
+
-- normal user can request self-service rotation without receiving broad IAM
|
|
4
|
+
-- permissions. Managers/admins can rotate keys for users they are allowed to
|
|
5
|
+
-- manage. Secret access keys remain encrypted at rest in IndraQ Cloud.
|
|
6
|
+
|
|
7
|
+
ALTER TABLE managed_aws_credentials
|
|
8
|
+
ADD COLUMN IF NOT EXISTS managed_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL;
|
|
9
|
+
|
|
10
|
+
UPDATE managed_aws_credentials
|
|
11
|
+
SET managed_by_user_id = created_by
|
|
12
|
+
WHERE managed_by_user_id IS NULL
|
|
13
|
+
AND created_by IS NOT NULL;
|
|
14
|
+
|
|
15
|
+
CREATE INDEX IF NOT EXISTS managed_aws_credentials_manager_idx
|
|
16
|
+
ON managed_aws_credentials(managed_by_user_id, cloud_user_id);
|
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
-- v2.1.0 provider scopes: organization-owned provider credentials with explicit
|
|
2
|
-
-- membership, per-user defaults, project/environment bindings and scope-aware
|
|
3
|
-
-- native identity tracking.
|
|
4
|
-
|
|
5
|
-
CREATE TABLE IF NOT EXISTS provider_scopes (
|
|
6
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
-
provider text NOT NULL CHECK (provider IN ('aws','npm','jenkins-dev','jenkins-prod','ghcr')),
|
|
8
|
-
name text NOT NULL,
|
|
9
|
-
description text,
|
|
10
|
-
company text,
|
|
11
|
-
config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
12
|
-
encrypted_secret text,
|
|
13
|
-
created_by uuid NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
|
|
14
|
-
is_active boolean NOT NULL DEFAULT true,
|
|
15
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
16
|
-
updated_at timestamptz NOT NULL DEFAULT now()
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
CREATE UNIQUE INDEX IF NOT EXISTS provider_scopes_provider_name_unique_idx
|
|
20
|
-
ON provider_scopes(provider, lower(name));
|
|
21
|
-
CREATE INDEX IF NOT EXISTS provider_scopes_provider_idx
|
|
22
|
-
ON provider_scopes(provider, is_active, created_at DESC);
|
|
23
|
-
|
|
24
|
-
CREATE TABLE IF NOT EXISTS provider_scope_members (
|
|
25
|
-
scope_id uuid NOT NULL REFERENCES provider_scopes(id) ON DELETE CASCADE,
|
|
26
|
-
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
27
|
-
access text NOT NULL CHECK (access IN ('use','manage')),
|
|
28
|
-
added_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
29
|
-
added_at timestamptz NOT NULL DEFAULT now(),
|
|
30
|
-
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
31
|
-
PRIMARY KEY(scope_id, user_id)
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
CREATE INDEX IF NOT EXISTS provider_scope_members_user_idx
|
|
35
|
-
ON provider_scope_members(user_id, scope_id);
|
|
36
|
-
|
|
37
|
-
CREATE TABLE IF NOT EXISTS user_scope_defaults (
|
|
38
|
-
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
39
|
-
provider text NOT NULL CHECK (provider IN ('aws','npm','jenkins-dev','jenkins-prod','ghcr')),
|
|
40
|
-
scope_id uuid NOT NULL REFERENCES provider_scopes(id) ON DELETE CASCADE,
|
|
41
|
-
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
42
|
-
PRIMARY KEY(user_id, provider)
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
CREATE TABLE IF NOT EXISTS project_environment_scopes (
|
|
46
|
-
project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
47
|
-
environment text NOT NULL,
|
|
48
|
-
provider text NOT NULL CHECK (provider IN ('aws','npm','jenkins-dev','jenkins-prod','ghcr')),
|
|
49
|
-
scope_id uuid NOT NULL REFERENCES provider_scopes(id) ON DELETE RESTRICT,
|
|
50
|
-
linked_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
51
|
-
linked_at timestamptz NOT NULL DEFAULT now(),
|
|
52
|
-
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
53
|
-
PRIMARY KEY(project_id, environment, provider)
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
CREATE INDEX IF NOT EXISTS project_environment_scopes_scope_idx
|
|
57
|
-
ON project_environment_scopes(scope_id, project_id, environment);
|
|
58
|
-
|
|
59
|
-
CREATE TABLE IF NOT EXISTS scope_external_accounts (
|
|
60
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
61
|
-
scope_id uuid NOT NULL REFERENCES provider_scopes(id) ON DELETE CASCADE,
|
|
62
|
-
cloud_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
63
|
-
provider text NOT NULL CHECK (provider IN ('npm','jenkins-dev','jenkins-prod')),
|
|
64
|
-
external_username text NOT NULL,
|
|
65
|
-
external_email text,
|
|
66
|
-
managed_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
67
|
-
config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
68
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
69
|
-
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
70
|
-
UNIQUE(scope_id, cloud_user_id)
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
CREATE INDEX IF NOT EXISTS scope_external_accounts_user_idx
|
|
74
|
-
ON scope_external_accounts(cloud_user_id, scope_id);
|
|
75
|
-
|
|
76
|
-
CREATE TABLE IF NOT EXISTS scope_aws_credentials (
|
|
77
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
78
|
-
scope_id uuid NOT NULL REFERENCES provider_scopes(id) ON DELETE CASCADE,
|
|
79
|
-
cloud_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
80
|
-
aws_username text NOT NULL,
|
|
81
|
-
access_key_id text NOT NULL UNIQUE,
|
|
82
|
-
encrypted_secret_access_key text NOT NULL,
|
|
83
|
-
indraq_role text NOT NULL CHECK (indraq_role IN ('user','manager','admin')),
|
|
84
|
-
managed_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
85
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
86
|
-
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
87
|
-
UNIQUE(scope_id, cloud_user_id)
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
CREATE INDEX IF NOT EXISTS scope_aws_credentials_user_idx
|
|
91
|
-
ON scope_aws_credentials(cloud_user_id, scope_id);
|
|
1
|
+
-- v2.1.0 provider scopes: organization-owned provider credentials with explicit
|
|
2
|
+
-- membership, per-user defaults, project/environment bindings and scope-aware
|
|
3
|
+
-- native identity tracking.
|
|
4
|
+
|
|
5
|
+
CREATE TABLE IF NOT EXISTS provider_scopes (
|
|
6
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
7
|
+
provider text NOT NULL CHECK (provider IN ('aws','npm','jenkins-dev','jenkins-prod','ghcr')),
|
|
8
|
+
name text NOT NULL,
|
|
9
|
+
description text,
|
|
10
|
+
company text,
|
|
11
|
+
config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
12
|
+
encrypted_secret text,
|
|
13
|
+
created_by uuid NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
|
|
14
|
+
is_active boolean NOT NULL DEFAULT true,
|
|
15
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
16
|
+
updated_at timestamptz NOT NULL DEFAULT now()
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
CREATE UNIQUE INDEX IF NOT EXISTS provider_scopes_provider_name_unique_idx
|
|
20
|
+
ON provider_scopes(provider, lower(name));
|
|
21
|
+
CREATE INDEX IF NOT EXISTS provider_scopes_provider_idx
|
|
22
|
+
ON provider_scopes(provider, is_active, created_at DESC);
|
|
23
|
+
|
|
24
|
+
CREATE TABLE IF NOT EXISTS provider_scope_members (
|
|
25
|
+
scope_id uuid NOT NULL REFERENCES provider_scopes(id) ON DELETE CASCADE,
|
|
26
|
+
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
27
|
+
access text NOT NULL CHECK (access IN ('use','manage')),
|
|
28
|
+
added_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
29
|
+
added_at timestamptz NOT NULL DEFAULT now(),
|
|
30
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
31
|
+
PRIMARY KEY(scope_id, user_id)
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
CREATE INDEX IF NOT EXISTS provider_scope_members_user_idx
|
|
35
|
+
ON provider_scope_members(user_id, scope_id);
|
|
36
|
+
|
|
37
|
+
CREATE TABLE IF NOT EXISTS user_scope_defaults (
|
|
38
|
+
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
39
|
+
provider text NOT NULL CHECK (provider IN ('aws','npm','jenkins-dev','jenkins-prod','ghcr')),
|
|
40
|
+
scope_id uuid NOT NULL REFERENCES provider_scopes(id) ON DELETE CASCADE,
|
|
41
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
42
|
+
PRIMARY KEY(user_id, provider)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
CREATE TABLE IF NOT EXISTS project_environment_scopes (
|
|
46
|
+
project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
47
|
+
environment text NOT NULL,
|
|
48
|
+
provider text NOT NULL CHECK (provider IN ('aws','npm','jenkins-dev','jenkins-prod','ghcr')),
|
|
49
|
+
scope_id uuid NOT NULL REFERENCES provider_scopes(id) ON DELETE RESTRICT,
|
|
50
|
+
linked_by uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
51
|
+
linked_at timestamptz NOT NULL DEFAULT now(),
|
|
52
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
53
|
+
PRIMARY KEY(project_id, environment, provider)
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
CREATE INDEX IF NOT EXISTS project_environment_scopes_scope_idx
|
|
57
|
+
ON project_environment_scopes(scope_id, project_id, environment);
|
|
58
|
+
|
|
59
|
+
CREATE TABLE IF NOT EXISTS scope_external_accounts (
|
|
60
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
61
|
+
scope_id uuid NOT NULL REFERENCES provider_scopes(id) ON DELETE CASCADE,
|
|
62
|
+
cloud_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
63
|
+
provider text NOT NULL CHECK (provider IN ('npm','jenkins-dev','jenkins-prod')),
|
|
64
|
+
external_username text NOT NULL,
|
|
65
|
+
external_email text,
|
|
66
|
+
managed_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
67
|
+
config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
68
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
69
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
70
|
+
UNIQUE(scope_id, cloud_user_id)
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
CREATE INDEX IF NOT EXISTS scope_external_accounts_user_idx
|
|
74
|
+
ON scope_external_accounts(cloud_user_id, scope_id);
|
|
75
|
+
|
|
76
|
+
CREATE TABLE IF NOT EXISTS scope_aws_credentials (
|
|
77
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
78
|
+
scope_id uuid NOT NULL REFERENCES provider_scopes(id) ON DELETE CASCADE,
|
|
79
|
+
cloud_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
80
|
+
aws_username text NOT NULL,
|
|
81
|
+
access_key_id text NOT NULL UNIQUE,
|
|
82
|
+
encrypted_secret_access_key text NOT NULL,
|
|
83
|
+
indraq_role text NOT NULL CHECK (indraq_role IN ('user','manager','admin')),
|
|
84
|
+
managed_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
85
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
86
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
87
|
+
UNIQUE(scope_id, cloud_user_id)
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
CREATE INDEX IF NOT EXISTS scope_aws_credentials_user_idx
|
|
91
|
+
ON scope_aws_credentials(cloud_user_id, scope_id);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- v2.2.0 hardening: per-user NPM/Jenkins secrets and project archive lifecycle.
|
|
2
|
+
|
|
3
|
+
ALTER TABLE scope_external_accounts
|
|
4
|
+
ADD COLUMN IF NOT EXISTS encrypted_secret text;
|
|
5
|
+
|
|
6
|
+
ALTER TABLE projects
|
|
7
|
+
ADD COLUMN IF NOT EXISTS archived_at timestamptz;
|
|
8
|
+
|
|
9
|
+
ALTER TABLE projects
|
|
10
|
+
ADD COLUMN IF NOT EXISTS archived_by uuid REFERENCES users(id) ON DELETE SET NULL;
|
|
11
|
+
|
|
12
|
+
CREATE INDEX IF NOT EXISTS projects_archived_at_idx
|
|
13
|
+
ON projects(archived_at, created_at DESC);
|