graphdb-workbench-tests 3.1.0-WBM-9 → 3.1.0-plugins1
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/.nycrc +10 -0
- package/cypress-legacy.config.js +9 -1
- package/cypress-security.config.js +40 -0
- package/cypress.config.js +3 -1
- package/e2e-flaky/import/import-user-data-url.spec.js +63 -0
- package/e2e-legacy/explore/graphs-overview/graphs.overview.spec.js +1 -1
- package/e2e-legacy/graphql/filter-graphql-endpoints-on-management-view.spec.js +1 -4
- package/e2e-legacy/graphql/graphql-endpoint-management-view.spec.js +4 -4
- package/e2e-legacy/graphql/import-graphql-endpoint-definitions.spec.js +1 -10
- package/e2e-legacy/home/cookie-policy.spec.js +78 -59
- package/e2e-legacy/home/documentation-link.spec.js +31 -33
- package/e2e-legacy/home/google-analytics.spec.js +4 -6
- package/e2e-legacy/home/rdf-resource-search.spec.js +106 -138
- package/e2e-legacy/home/view-resource-autocomplete.spec.js +28 -15
- package/e2e-legacy/import/import-user-data-url.spec.js +0 -23
- package/e2e-legacy/import/import-user-data.spec.js +1 -2
- package/e2e-legacy/monitor/global-operation-statuses-component.spec.js +13 -9
- package/e2e-legacy/repository/repositories.spec.js +6 -6
- package/e2e-legacy/setup/autocomplete/autocomplete.spec.js +3 -4
- package/e2e-legacy/setup/jdbc/jdbc-create.spec.js +2 -2
- package/e2e-legacy/setup/sparql-template/sparql-template-create.js +10 -3
- package/e2e-legacy/setup/users-and-access/user-and-access.spec.js +38 -9
- package/e2e-legacy/sparql-editor/saved-query/edit-query.spec.js +3 -6
- package/e2e-legacy/sparql-editor/saved-query/share-query.spec.js +2 -2
- package/e2e-legacy/ttyg/agent-list.spec.js +37 -2
- package/e2e-legacy/ttyg/chat-list.spec.js +1 -2
- package/e2e-legacy/ttyg/clone-agent.spec.js +1 -0
- package/e2e-legacy/ttyg/create-agent.spec.js +7 -6
- package/e2e-legacy/ttyg/edit-agent.spec.js +69 -9
- package/e2e-legacy/ttyg/ttyg-initial-state-with-selected-repository.spec.js +4 -2
- package/e2e-legacy/ttyg/ttyg-permission.spec.js +28 -20
- package/e2e-security/setup/home/cookie-policy.spec.js +64 -0
- package/e2e-security/setup/users-and-access/create-user-permissions.spec.js +184 -0
- package/e2e-security/setup/users-and-access/graphql-user.spec.js +123 -0
- package/e2e-security/setup/users-and-access/repo-admin-role.spec.js +69 -0
- package/e2e-security/setup/users-and-access/turn-on-security-and-password-change.spec.js +87 -0
- package/e2e-security/setup/users-and-access/user-and-access.spec.js +87 -0
- package/e2e-security/setup/users-and-access/users-and-access-initial-state.spec.js +38 -0
- package/fixtures/repositories/free-access.json +13 -0
- package/fixtures/ttyg/agent/get-agent-defaults-assistant-api.json +44 -0
- package/fixtures/ttyg/agent/get-agent-defaults.json +2 -0
- package/npm-shrinkwrap.json +7574 -1775
- package/package.json +9 -3
- package/plugins/index.js +1 -0
- package/steps/base-steps.js +4 -0
- package/steps/error-steps.js +4 -7
- package/steps/graphql/graphql-endpoint-management-steps.js +1 -1
- package/steps/home-steps.js +57 -32
- package/steps/import/import-steps.js +2 -2
- package/steps/login-steps.js +11 -0
- package/steps/main-menu-steps.js +13 -6
- package/steps/operations-statuses-component-steps.js +5 -10
- package/steps/rdf-resource-search-steps.js +55 -0
- package/steps/repository-steps.js +1 -0
- package/steps/setup/autocomplete-steps.js +4 -0
- package/steps/setup/settings-steps.js +18 -0
- package/steps/setup/user-and-access-steps.js +24 -2
- package/steps/ttyg/ttyg-agent-settings-modal.steps.js +74 -11
- package/steps/ttyg/ttyg-view-steps.js +19 -4
- package/steps/widgets/active-repository-widget-steps.js +4 -0
- package/steps/yasgui/yasr-steps.js +4 -0
- package/stubs/browser-stubs.js +21 -0
- package/stubs/environment-stubs.js +9 -1
- package/stubs/repositories/repositories-stubs.js +4 -0
- package/stubs/security-stubs.js +4 -0
- package/stubs/ttyg/ttyg-stubs.js +18 -2
- package/support/e2e.js +2 -1
- package/support/repository-commands.js +14 -1
- package/e2e-flaky/setup/users-and-access/security-and-free-access.spec.js +0 -57
- package/e2e-flaky/ttyg/ttyg-permission.spec.js +0 -67
- package/fixtures/locale-en.json +0 -3361
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { MainMenuSteps } from "../../../steps/main-menu-steps";
|
|
2
|
+
import {UserAndAccessSteps} from "../../../steps/setup/user-and-access-steps";
|
|
3
|
+
import { LoginSteps } from "../../../steps/login-steps";
|
|
4
|
+
import {ToasterSteps} from "../../../steps/toaster-steps";
|
|
5
|
+
import {YasqeSteps} from "../../../steps/yasgui/yasqe-steps";
|
|
6
|
+
import {YasrSteps} from "../../../steps/yasgui/yasr-steps";
|
|
7
|
+
|
|
8
|
+
describe('User Management – Creation, Validation, Permissions & Deletion', () => {
|
|
9
|
+
let repositoryId;
|
|
10
|
+
const testPassword = 'P@ssw0rd123!';
|
|
11
|
+
const testUsername = `testuser-${Date.now()}`;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
// Create and initialize a fresh repository for isolation
|
|
15
|
+
repositoryId = `repo-${Date.now()}`;
|
|
16
|
+
cy.createRepository({ id: repositoryId });
|
|
17
|
+
cy.presetRepository(repositoryId);
|
|
18
|
+
cy.initializeRepository(repositoryId);
|
|
19
|
+
|
|
20
|
+
// Navigate to Users & Access
|
|
21
|
+
UserAndAccessSteps.visit();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
// Clean up repository
|
|
26
|
+
cy.deleteRepository(repositoryId);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('Create a new user – validation', () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
UserAndAccessSteps.clickCreateNewUserButton();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should show error when username is empty', () => {
|
|
35
|
+
UserAndAccessSteps.typePassword(testPassword);
|
|
36
|
+
UserAndAccessSteps.typeConfirmPasswordField(testPassword);
|
|
37
|
+
UserAndAccessSteps.clickReadAccessRepo(repositoryId);
|
|
38
|
+
UserAndAccessSteps.clickWriteAccessRepo(repositoryId);
|
|
39
|
+
UserAndAccessSteps.confirmUserCreate();
|
|
40
|
+
UserAndAccessSteps.getUserFieldError('username').should('be.visible').and('contain.text', 'Enter username!');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should show error when passwords are empty', () => {
|
|
44
|
+
UserAndAccessSteps.typeUsername(testUsername);
|
|
45
|
+
UserAndAccessSteps.confirmUserCreate();
|
|
46
|
+
UserAndAccessSteps.getUserFieldError('password').should('be.visible').and('contain.text', 'Enter password!');
|
|
47
|
+
UserAndAccessSteps.getUserFieldError('confirmPassword').should('be.visible').and('contain.text', 'Confirm password!');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should show error when passwords do not match', () => {
|
|
51
|
+
UserAndAccessSteps.typeUsername(testUsername);
|
|
52
|
+
UserAndAccessSteps.typePassword(testPassword);
|
|
53
|
+
UserAndAccessSteps.typeConfirmPasswordField('Different123!');
|
|
54
|
+
UserAndAccessSteps.clickReadAccessRepo(repositoryId);
|
|
55
|
+
UserAndAccessSteps.clickWriteAccessRepo(repositoryId);
|
|
56
|
+
UserAndAccessSteps.confirmUserCreate();
|
|
57
|
+
UserAndAccessSteps.getUserFieldError('confirmPassword').should('be.visible').and('contain.text', 'Confirm password!');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should show error when username duplicates existing one', () => {
|
|
61
|
+
UserAndAccessSteps.typeUsername('user');
|
|
62
|
+
UserAndAccessSteps.typePassword(testPassword);
|
|
63
|
+
UserAndAccessSteps.typeConfirmPasswordField(testPassword);
|
|
64
|
+
UserAndAccessSteps.clickReadAccessRepo(repositoryId);
|
|
65
|
+
UserAndAccessSteps.clickWriteAccessRepo(repositoryId);
|
|
66
|
+
UserAndAccessSteps.confirmUserCreate();
|
|
67
|
+
|
|
68
|
+
cy.url().should('include', '/users');
|
|
69
|
+
UserAndAccessSteps.clickCreateNewUserButton();
|
|
70
|
+
UserAndAccessSteps.typeUsername('user');
|
|
71
|
+
UserAndAccessSteps.typePassword(testPassword);
|
|
72
|
+
UserAndAccessSteps.typeConfirmPasswordField(testPassword);
|
|
73
|
+
UserAndAccessSteps.clickWriteAccessRepo(repositoryId);
|
|
74
|
+
UserAndAccessSteps.confirmUserCreate();
|
|
75
|
+
|
|
76
|
+
ToasterSteps.verifyError('An account with the given username already exists.');
|
|
77
|
+
cy.deleteUser('user');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should show error when no repository read access is given', () => {
|
|
81
|
+
UserAndAccessSteps.typeUsername(testUsername);
|
|
82
|
+
UserAndAccessSteps.typePassword(testPassword);
|
|
83
|
+
UserAndAccessSteps.typeConfirmPasswordField(testPassword);
|
|
84
|
+
UserAndAccessSteps.confirmUserCreate();
|
|
85
|
+
UserAndAccessSteps.getRepositoryRightsError().should('be.visible').and('contain.text', 'Users should have rights to at least one repository!');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should show error when custom role is too short', () => {
|
|
89
|
+
UserAndAccessSteps.typeUsername(testUsername);
|
|
90
|
+
UserAndAccessSteps.typePassword(testPassword);
|
|
91
|
+
UserAndAccessSteps.typeConfirmPasswordField(testPassword);
|
|
92
|
+
UserAndAccessSteps.addTextToCustomRoleField('a');
|
|
93
|
+
UserAndAccessSteps.clickReadAccessRepo(repositoryId);
|
|
94
|
+
UserAndAccessSteps.clickWriteAccessRepo(repositoryId);
|
|
95
|
+
UserAndAccessSteps.getCustomRoleFieldError().should('be.visible').and('contain.text', 'Must be at least 2 symbols long');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('Create a new user – read/write access', () => {
|
|
100
|
+
const rwUsername = `rwuser-${Date.now()}`;
|
|
101
|
+
|
|
102
|
+
afterEach(() =>{
|
|
103
|
+
cy.loginAsAdmin();
|
|
104
|
+
cy.switchOffSecurity(true);
|
|
105
|
+
cy.deleteUser(rwUsername);
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('should create, login, and verify permissions', () => {
|
|
109
|
+
UserAndAccessSteps.clickCreateNewUserButton();
|
|
110
|
+
UserAndAccessSteps.typeUsername(rwUsername);
|
|
111
|
+
UserAndAccessSteps.typePassword(testPassword);
|
|
112
|
+
UserAndAccessSteps.typeConfirmPasswordField(testPassword);
|
|
113
|
+
UserAndAccessSteps.clickReadAccessRepo(repositoryId);
|
|
114
|
+
UserAndAccessSteps.clickWriteAccessRepo(repositoryId);
|
|
115
|
+
UserAndAccessSteps.getWriteAccessForRepo(repositoryId).should('be.checked');
|
|
116
|
+
UserAndAccessSteps.confirmUserCreate();
|
|
117
|
+
UserAndAccessSteps.toggleSecurity();
|
|
118
|
+
|
|
119
|
+
LoginSteps.loginWithUser(rwUsername, testPassword);
|
|
120
|
+
// RepositorySteps.selectRepoFromDropdown(repositoryId);
|
|
121
|
+
MainMenuSteps.clickOnSparqlMenu();
|
|
122
|
+
|
|
123
|
+
YasqeSteps.clearEditor();
|
|
124
|
+
const prefix = 'PREFIX ex: <http://example.org/>\n';
|
|
125
|
+
const query = 'INSERT DATA {\n' +
|
|
126
|
+
'ex:greeting ex:text "Hello, world!" .\n' +
|
|
127
|
+
'}';
|
|
128
|
+
cy.pasteIntoCodeMirror('.CodeMirror', prefix + query);
|
|
129
|
+
YasqeSteps.executeQueryWithoutWaiteResult();
|
|
130
|
+
// Verify read access
|
|
131
|
+
YasrSteps.getResponseInfo()
|
|
132
|
+
.should('not.have.class', 'hidden')
|
|
133
|
+
.should('not.have.class', 'empty')
|
|
134
|
+
.should('be.visible')
|
|
135
|
+
.should('contain.text', 'Added 1 statements.');
|
|
136
|
+
|
|
137
|
+
LoginSteps.logout();
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('Create a new user – read only access', () => {
|
|
142
|
+
const roUsername = `rouser-${Date.now()}`;
|
|
143
|
+
|
|
144
|
+
afterEach(() =>{
|
|
145
|
+
cy.loginAsAdmin();
|
|
146
|
+
cy.switchOffSecurity(true);
|
|
147
|
+
cy.deleteUser(roUsername);
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('should create, login, and verify read-only', () => {
|
|
151
|
+
UserAndAccessSteps.clickCreateNewUserButton();
|
|
152
|
+
UserAndAccessSteps.typeUsername(roUsername);
|
|
153
|
+
UserAndAccessSteps.typePassword(testPassword);
|
|
154
|
+
UserAndAccessSteps.typeConfirmPasswordField(testPassword);
|
|
155
|
+
UserAndAccessSteps.clickReadAccessRepo(repositoryId);
|
|
156
|
+
UserAndAccessSteps.getReadAccessForRepo(repositoryId).should('be.checked');
|
|
157
|
+
UserAndAccessSteps.getWriteAccessForRepo(repositoryId).should('not.be.checked');
|
|
158
|
+
UserAndAccessSteps.confirmUserCreate();
|
|
159
|
+
UserAndAccessSteps.toggleSecurity();
|
|
160
|
+
|
|
161
|
+
LoginSteps.loginWithUser(roUsername, testPassword);
|
|
162
|
+
MainMenuSteps.clickOnSparqlMenu();
|
|
163
|
+
|
|
164
|
+
YasqeSteps.clearEditor();
|
|
165
|
+
const prefix = 'PREFIX ex: <http://example.org/>\n';
|
|
166
|
+
const query = 'INSERT DATA {\n' +
|
|
167
|
+
'ex:greeting ex:text "Hello, world!" .\n' +
|
|
168
|
+
'}';
|
|
169
|
+
cy.pasteIntoCodeMirror('.CodeMirror', prefix + query);
|
|
170
|
+
// Verify no write access
|
|
171
|
+
YasqeSteps.executeErrorQuery();
|
|
172
|
+
|
|
173
|
+
YasqeSteps.clearEditor();
|
|
174
|
+
const readQuery = 'select * where {\n' +
|
|
175
|
+
'?s ?p ?o .\n' +
|
|
176
|
+
'} limit 100';
|
|
177
|
+
cy.pasteIntoCodeMirror('.CodeMirror', readQuery);
|
|
178
|
+
// Verify read accessorQuery();
|
|
179
|
+
YasqeSteps.executeQuery();
|
|
180
|
+
|
|
181
|
+
LoginSteps.logout();
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {UserAndAccessSteps} from "../../../steps/setup/user-and-access-steps";
|
|
2
|
+
import {LoginSteps} from "../../../steps/login-steps";
|
|
3
|
+
import {GraphqlPlaygroundSteps} from "../../../steps/graphql/graphql-playground-steps";
|
|
4
|
+
import {RepositorySteps} from "../../../steps/repository-steps";
|
|
5
|
+
|
|
6
|
+
describe('GraphQL-only User – Playground Access & Mutation Restriction', () => {
|
|
7
|
+
let repositoryId;
|
|
8
|
+
const gqlUsername = `gqluser-${Date.now()}`;
|
|
9
|
+
const testPassword = 'P@ssw0rd123!';
|
|
10
|
+
const readQuery = `
|
|
11
|
+
query StarshipById {
|
|
12
|
+
starship(ID: "https://swapi.co/resource/starship/9") {
|
|
13
|
+
name
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
const mutation = `
|
|
18
|
+
mutation CreateHuman {
|
|
19
|
+
create_Human(
|
|
20
|
+
objects: [
|
|
21
|
+
{
|
|
22
|
+
id: "file:/test/onto/vocabulary/Human1",
|
|
23
|
+
rdfs_label: "New human with specific iri id"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
) {
|
|
27
|
+
human { id }
|
|
28
|
+
affected_objects { ids }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
repositoryId = `repo-${Date.now()}`;
|
|
35
|
+
cy.createRepository({ id: repositoryId });
|
|
36
|
+
cy.presetRepository(repositoryId);
|
|
37
|
+
cy.importServerFile(repositoryId, 'swapi-dataset.ttl');
|
|
38
|
+
cy.uploadGraphqlSchema(repositoryId, 'graphql/soml/swapi-schema.yaml', 'swapi');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
cy.loginAsAdmin();
|
|
43
|
+
cy.switchOffSecurity(true);
|
|
44
|
+
cy.deleteUser(gqlUsername);
|
|
45
|
+
cy.deleteRepository(repositoryId);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should see only the assigned repo, block SPARQL, allow GraphQL read and forbid writes, and hide create-repo everywhere', () => {
|
|
49
|
+
UserAndAccessSteps.visit();
|
|
50
|
+
UserAndAccessSteps.clickCreateNewUserButton();
|
|
51
|
+
UserAndAccessSteps.typeUsername(gqlUsername);
|
|
52
|
+
UserAndAccessSteps.typePassword(testPassword);
|
|
53
|
+
UserAndAccessSteps.typeConfirmPasswordField(testPassword);
|
|
54
|
+
UserAndAccessSteps.clickReadAccessRepo(repositoryId);
|
|
55
|
+
UserAndAccessSteps.clickGraphqlAccessRepo(repositoryId);
|
|
56
|
+
UserAndAccessSteps.confirmUserCreate();
|
|
57
|
+
|
|
58
|
+
UserAndAccessSteps.toggleSecurity();
|
|
59
|
+
|
|
60
|
+
// Log in as GraphQL-only user
|
|
61
|
+
LoginSteps.loginWithUser(gqlUsername, testPassword);
|
|
62
|
+
RepositorySteps.selectRepoFromDropdown(repositoryId);
|
|
63
|
+
// Verify only the assigned repository appears in endpoints
|
|
64
|
+
GraphqlPlaygroundSteps.visit();
|
|
65
|
+
GraphqlPlaygroundSteps.getView().should('be.visible');
|
|
66
|
+
GraphqlPlaygroundSteps.getQueryEditor().should('be.visible');
|
|
67
|
+
GraphqlPlaygroundSteps.getSelectedEndpoint().should('have.text', 'swapi');
|
|
68
|
+
// And I can execute a query on the countries endpoint
|
|
69
|
+
GraphqlPlaygroundSteps.setInEditor(readQuery);
|
|
70
|
+
// And I execute the query
|
|
71
|
+
GraphqlPlaygroundSteps.executeQuery();
|
|
72
|
+
// Then I get expected result
|
|
73
|
+
GraphqlPlaygroundSteps.getResponse().should('contain', '"name": "Death Star"');
|
|
74
|
+
|
|
75
|
+
// Execute the create_Human mutation → expect errors
|
|
76
|
+
GraphqlPlaygroundSteps.setInEditor(mutation);
|
|
77
|
+
GraphqlPlaygroundSteps.executeQuery();
|
|
78
|
+
GraphqlPlaygroundSteps.getResponse().should('contain.text', 'errors');
|
|
79
|
+
LoginSteps.logout();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should allow GraphQL mutation and hide SPARQL/Import/Create-repo menus', () => {
|
|
83
|
+
UserAndAccessSteps.visit();
|
|
84
|
+
UserAndAccessSteps.clickCreateNewUserButton();
|
|
85
|
+
UserAndAccessSteps.typeUsername(gqlUsername);
|
|
86
|
+
UserAndAccessSteps.typePassword(testPassword);
|
|
87
|
+
UserAndAccessSteps.typeConfirmPasswordField(testPassword);
|
|
88
|
+
UserAndAccessSteps.clickReadAccessRepo(repositoryId);
|
|
89
|
+
UserAndAccessSteps.clickWriteAccessRepo(repositoryId);
|
|
90
|
+
UserAndAccessSteps.clickGraphqlAccessRepo(repositoryId);
|
|
91
|
+
UserAndAccessSteps.confirmUserCreate();
|
|
92
|
+
|
|
93
|
+
UserAndAccessSteps.toggleSecurity();
|
|
94
|
+
|
|
95
|
+
// Log in as the new user
|
|
96
|
+
LoginSteps.loginWithUser(gqlUsername, testPassword);
|
|
97
|
+
|
|
98
|
+
// Select the repo in the navbar
|
|
99
|
+
RepositorySteps.selectRepoFromDropdown(repositoryId);
|
|
100
|
+
|
|
101
|
+
// Visit GraphQL Playground
|
|
102
|
+
GraphqlPlaygroundSteps.visit();
|
|
103
|
+
GraphqlPlaygroundSteps.getView().should('be.visible');
|
|
104
|
+
GraphqlPlaygroundSteps.getQueryEditor().should('be.visible');
|
|
105
|
+
GraphqlPlaygroundSteps.getSelectedEndpoint().should('have.text', 'swapi');
|
|
106
|
+
|
|
107
|
+
// Execute a read query to verify read access
|
|
108
|
+
GraphqlPlaygroundSteps.setInEditor(readQuery);
|
|
109
|
+
GraphqlPlaygroundSteps.executeQuery();
|
|
110
|
+
GraphqlPlaygroundSteps.getResponse()
|
|
111
|
+
.should('contain.text', '"name": "Death Star"');
|
|
112
|
+
|
|
113
|
+
// Execute the mutation and expect success
|
|
114
|
+
GraphqlPlaygroundSteps.setInEditor(mutation);
|
|
115
|
+
GraphqlPlaygroundSteps.executeQuery();
|
|
116
|
+
GraphqlPlaygroundSteps.getResponse()
|
|
117
|
+
.should('contain.text', 'data')
|
|
118
|
+
.and('contain.text', 'create_Human')
|
|
119
|
+
.and('contain.text', 'affected_objects');
|
|
120
|
+
|
|
121
|
+
LoginSteps.logout();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {UserAndAccessSteps} from "../../../steps/setup/user-and-access-steps";
|
|
2
|
+
import {LoginSteps} from "../../../steps/login-steps";
|
|
3
|
+
import {YasqeSteps} from "../../../steps/yasgui/yasqe-steps";
|
|
4
|
+
import {YasrSteps} from "../../../steps/yasgui/yasr-steps";
|
|
5
|
+
import {MainMenuSteps} from "../../../steps/main-menu-steps";
|
|
6
|
+
import HomeSteps from "../../../steps/home-steps";
|
|
7
|
+
import {ActiveRepositoryWidgetSteps} from "../../../steps/widgets/active-repository-widget-steps";
|
|
8
|
+
|
|
9
|
+
describe('Repository Admin – Permissions and Access Control', () => {
|
|
10
|
+
const repoAdminUsername = `repoadmin-${Date.now()}`;
|
|
11
|
+
const password = 'Admin123!';
|
|
12
|
+
let repositoryId;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
repositoryId = `repo-${Date.now()}`;
|
|
16
|
+
cy.createRepository({ id: repositoryId });
|
|
17
|
+
cy.presetRepository(repositoryId);
|
|
18
|
+
cy.initializeRepository(repositoryId);
|
|
19
|
+
|
|
20
|
+
UserAndAccessSteps.visit();
|
|
21
|
+
UserAndAccessSteps.clickCreateNewUserButton();
|
|
22
|
+
UserAndAccessSteps.typeUsername(repoAdminUsername);
|
|
23
|
+
UserAndAccessSteps.typePassword(password);
|
|
24
|
+
UserAndAccessSteps.typeConfirmPasswordField(password);
|
|
25
|
+
UserAndAccessSteps.selectRoleRadioButton('#roleRepoAdmin');
|
|
26
|
+
|
|
27
|
+
UserAndAccessSteps.getReadAccessForRepo('*').should('be.checked').and('be.disabled');
|
|
28
|
+
UserAndAccessSteps.getWriteAccessForRepo('*').should('be.checked').and('be.disabled');
|
|
29
|
+
|
|
30
|
+
UserAndAccessSteps.confirmUserCreate();
|
|
31
|
+
UserAndAccessSteps.toggleSecurity();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
cy.loginAsAdmin();
|
|
36
|
+
cy.switchOffSecurity(true);
|
|
37
|
+
cy.deleteUser(repoAdminUsername);
|
|
38
|
+
cy.deleteRepository(repositoryId);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('Repository admin has correct access and restrictions', () => {
|
|
42
|
+
LoginSteps.loginWithUser(repoAdminUsername, password);
|
|
43
|
+
|
|
44
|
+
// SPARQL – read access
|
|
45
|
+
MainMenuSteps.clickOnSparqlMenu();
|
|
46
|
+
|
|
47
|
+
YasqeSteps.getEditor().should('be.visible');
|
|
48
|
+
YasqeSteps.executeQuery();
|
|
49
|
+
|
|
50
|
+
// SPARQL – write access
|
|
51
|
+
YasqeSteps.clearEditor();
|
|
52
|
+
const prefix = 'PREFIX ex: <http://example.org/>\n';
|
|
53
|
+
const query = 'INSERT DATA {\n' +
|
|
54
|
+
'ex:greeting ex:text "Hello, world!" .\n' +
|
|
55
|
+
'}';
|
|
56
|
+
cy.pasteIntoCodeMirror('.CodeMirror', prefix + query);
|
|
57
|
+
YasqeSteps.executeQueryWithoutWaiteResult();
|
|
58
|
+
// Verify read access
|
|
59
|
+
YasrSteps.getResponseInfo()
|
|
60
|
+
.should('not.have.class', 'hidden')
|
|
61
|
+
.should('not.have.class', 'empty')
|
|
62
|
+
.should('be.visible')
|
|
63
|
+
.should('contain.text', 'Added 1 statements.');
|
|
64
|
+
|
|
65
|
+
// Create repo button on homepage should be visible
|
|
66
|
+
HomeSteps.visit();
|
|
67
|
+
ActiveRepositoryWidgetSteps.getImportLink().scrollIntoView().should('be.visible').and('not.be.disabled');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {MainMenuSteps} from "../../../steps/main-menu-steps";
|
|
2
|
+
import {UserAndAccessSteps} from "../../../steps/setup/user-and-access-steps";
|
|
3
|
+
import {LoginSteps} from "../../../steps/login-steps";
|
|
4
|
+
import {ToasterSteps} from "../../../steps/toaster-steps";
|
|
5
|
+
|
|
6
|
+
describe('Turn on Security', () => {
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
cy.loginAsAdmin();
|
|
10
|
+
cy.switchOnSecurity();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
afterEach(() =>{
|
|
14
|
+
cy.loginAsAdmin();
|
|
15
|
+
cy.switchOffSecurity(true);
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('should enable security and show login screen with only Help accessible', () => {
|
|
19
|
+
// Navigate to Users & Access
|
|
20
|
+
UserAndAccessSteps.visit();
|
|
21
|
+
// Verify we are redirected to login page
|
|
22
|
+
cy.url().should('include', '/login');
|
|
23
|
+
MainMenuSteps.getMenuHelp().should('not.exist');
|
|
24
|
+
MainMenuSteps.getMenuExplore().should('not.exist');
|
|
25
|
+
MainMenuSteps.getMenuMonitoring().should('not.exist');
|
|
26
|
+
MainMenuSteps.getMenuSetup().should('not.exist');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should reject wrong credentials and accept admin/root', () => {
|
|
30
|
+
// Attempt login with invalid credentials
|
|
31
|
+
LoginSteps.visitLoginPage();
|
|
32
|
+
LoginSteps.loginWithUser('wrongUser', 'wrongPass');
|
|
33
|
+
// Expect error message
|
|
34
|
+
ToasterSteps.verifyError('Wrong credentials');
|
|
35
|
+
|
|
36
|
+
// Login with correct admin credentials
|
|
37
|
+
LoginSteps.visitLoginPage();
|
|
38
|
+
LoginSteps.loginWithUser('admin', 'root');
|
|
39
|
+
cy.url().should('include', '/');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should change admin password and enforce new credentials', () => {
|
|
43
|
+
// Navigate to Users & Access after login
|
|
44
|
+
UserAndAccessSteps.visit();
|
|
45
|
+
// Verify we are redirected to login page
|
|
46
|
+
cy.url().should('include', '/login');
|
|
47
|
+
LoginSteps.loginWithUser('admin', 'root');
|
|
48
|
+
|
|
49
|
+
// Open edit page for admin user
|
|
50
|
+
UserAndAccessSteps.openEditUserPage('admin');
|
|
51
|
+
|
|
52
|
+
// Change password to a new value
|
|
53
|
+
let newPassword = 'MyNewP@ssw0rd!';
|
|
54
|
+
UserAndAccessSteps.typePassword(newPassword);
|
|
55
|
+
UserAndAccessSteps.typeConfirmPasswordField(newPassword);
|
|
56
|
+
UserAndAccessSteps.confirmUserEdit();
|
|
57
|
+
|
|
58
|
+
// Log out
|
|
59
|
+
LoginSteps.logout();
|
|
60
|
+
cy.url().should('include', '/login');
|
|
61
|
+
|
|
62
|
+
// Attempt login with old password
|
|
63
|
+
LoginSteps.loginWithUser('admin', 'root');
|
|
64
|
+
ToasterSteps.verifyError('Wrong credentials');
|
|
65
|
+
|
|
66
|
+
// Attempt login with new password
|
|
67
|
+
LoginSteps.visitLoginPage();
|
|
68
|
+
LoginSteps.loginWithUser('admin', newPassword);
|
|
69
|
+
UserAndAccessSteps.visit();
|
|
70
|
+
// Open edit page for admin user
|
|
71
|
+
UserAndAccessSteps.openEditUserPage('admin');
|
|
72
|
+
newPassword = 'root';
|
|
73
|
+
UserAndAccessSteps.typePassword(newPassword);
|
|
74
|
+
UserAndAccessSteps.typeConfirmPasswordField(newPassword);
|
|
75
|
+
UserAndAccessSteps.confirmUserEdit();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should show toaster when after logging out', () => {
|
|
79
|
+
UserAndAccessSteps.visit();
|
|
80
|
+
LoginSteps.loginWithUser('admin', 'root');
|
|
81
|
+
// Log out
|
|
82
|
+
LoginSteps.logout();
|
|
83
|
+
cy.url().should('include', '/login');
|
|
84
|
+
// Verify toaster message
|
|
85
|
+
ToasterSteps.verifySuccess('Signed out');
|
|
86
|
+
})
|
|
87
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {RepositoriesStubs} from "../../../stubs/repositories/repositories-stubs";
|
|
2
|
+
import {UserAndAccessSteps} from "../../../steps/setup/user-and-access-steps";
|
|
3
|
+
import {LoginSteps} from "../../../steps/login-steps";
|
|
4
|
+
import {ModalDialogSteps} from "../../../steps/modal-dialog-steps";
|
|
5
|
+
import ImportSteps from "../../../steps/import/import-steps";
|
|
6
|
+
import {MainMenuSteps} from "../../../steps/main-menu-steps";
|
|
7
|
+
import {RepositorySelectorSteps} from "../../../steps/repository-selector-steps";
|
|
8
|
+
import {ErrorSteps} from "../../../steps/error-steps";
|
|
9
|
+
|
|
10
|
+
describe('User and Access', () => {
|
|
11
|
+
|
|
12
|
+
let repositoryId1;
|
|
13
|
+
let repositoryId2;
|
|
14
|
+
const graphqlUser = 'graphqlUser';
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
cy.viewport(1280, 1000);
|
|
18
|
+
RepositoriesStubs.spyGetRepositories();
|
|
19
|
+
repositoryId1 = 'user-access-repo1-' + Date.now();
|
|
20
|
+
repositoryId2 = 'user-access-repo2-' + Date.now();
|
|
21
|
+
cy.createRepository({id: repositoryId1});
|
|
22
|
+
cy.createRepository({id: repositoryId2});
|
|
23
|
+
cy.presetRepository(repositoryId1);
|
|
24
|
+
UserAndAccessSteps.visit();
|
|
25
|
+
// Users table should be visible
|
|
26
|
+
UserAndAccessSteps.getUsersTable().should('be.visible');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
cy.loginAsAdmin().then(() => {
|
|
31
|
+
cy.deleteRepository(repositoryId1, true);
|
|
32
|
+
cy.deleteRepository(repositoryId2, true);
|
|
33
|
+
cy.deleteUser(graphqlUser, true);
|
|
34
|
+
cy.switchOffFreeAccess(true);
|
|
35
|
+
cy.switchOffSecurity(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should restrict page when free access in on', () => {
|
|
41
|
+
// Given: There at least two repositories.
|
|
42
|
+
// When: I enable the security
|
|
43
|
+
UserAndAccessSteps.toggleSecurity();
|
|
44
|
+
LoginSteps.loginWithUser('admin', 'root');
|
|
45
|
+
// And: turn on Free Access
|
|
46
|
+
UserAndAccessSteps.getFreeAccessSwitchInput().should('not.be.checked');
|
|
47
|
+
UserAndAccessSteps.toggleFreeAccess();
|
|
48
|
+
// And: set graphql rights for the second repository when free access is ON
|
|
49
|
+
UserAndAccessSteps.clickFreeWriteAccessRepo(repositoryId2);
|
|
50
|
+
UserAndAccessSteps.clickFreeGraphqlAccessRepo(repositoryId2);
|
|
51
|
+
ModalDialogSteps.clickOKButton();
|
|
52
|
+
|
|
53
|
+
// When: I logout
|
|
54
|
+
LoginSteps.logout();
|
|
55
|
+
// And: repository with graphql rights is selected
|
|
56
|
+
RepositorySelectorSteps.selectRepository(repositoryId2);
|
|
57
|
+
// And: I click on the Import menu.
|
|
58
|
+
MainMenuSteps.clickOnMenuImport();
|
|
59
|
+
|
|
60
|
+
// Then: I should see the error message, because import view is available only for write access, repositoryId2 has only graphql rights.
|
|
61
|
+
ErrorSteps.verifyError('Some functionalities are not available because you do not have the required repository permissions.')
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should restrict the repositories depending on whether free access is enabled and whether the user is logged in', () => {
|
|
65
|
+
// Given: There at least two repositories.
|
|
66
|
+
// When: I enable the security
|
|
67
|
+
UserAndAccessSteps.toggleSecurity();
|
|
68
|
+
LoginSteps.loginWithUser('admin', 'root');
|
|
69
|
+
// And: turn on Free Access
|
|
70
|
+
UserAndAccessSteps.toggleFreeAccess();
|
|
71
|
+
// And: set rights for the second repository when free access is ON
|
|
72
|
+
UserAndAccessSteps.clickFreeWriteAccessRepo(repositoryId2);
|
|
73
|
+
ModalDialogSteps.clickOKButton();
|
|
74
|
+
|
|
75
|
+
// When: I logout
|
|
76
|
+
LoginSteps.logout();
|
|
77
|
+
// Then: I should see only repositoryId2, as it is the only one configured for free access
|
|
78
|
+
RepositorySelectorSteps.getRepositorySelectorButton(repositoryId1).should('not.exist');
|
|
79
|
+
RepositorySelectorSteps.getRepositorySelectorButton(repositoryId2).should('exist');
|
|
80
|
+
|
|
81
|
+
// When: I log in again with a user who has access to all repositories
|
|
82
|
+
LoginSteps.loginWithUser('admin', 'root');
|
|
83
|
+
// Then: I should see both repositories in the repository selector, because the user has access to all repositories
|
|
84
|
+
RepositorySelectorSteps.getRepositorySelectorButton(repositoryId1).should('exist');
|
|
85
|
+
RepositorySelectorSteps.getRepositorySelectorButton(repositoryId2).should('exist');
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {UserAndAccessSteps} from "../../../steps/setup/user-and-access-steps";
|
|
2
|
+
import {MainMenuSteps} from "../../../steps/main-menu-steps";
|
|
3
|
+
|
|
4
|
+
describe('Users and Access initial state', () => {
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
cy.intercept('GET', '**/rest/security/users').as('getUsers');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('Should display the correct initial state when navigating via URL', () => {
|
|
10
|
+
// Given, I visit the Users and Access page via URL
|
|
11
|
+
UserAndAccessSteps.visit();
|
|
12
|
+
// Then,
|
|
13
|
+
validateInitialState();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('Should display the correct initial state when navigating via the navigation menu', () => {
|
|
17
|
+
// Given, I visit the Users and Access page via the navigation menu
|
|
18
|
+
UserAndAccessSteps.visit();
|
|
19
|
+
MainMenuSteps.clickOnUsersAndAccess();
|
|
20
|
+
// Then,
|
|
21
|
+
validateInitialState();
|
|
22
|
+
});
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
function validateInitialState() {
|
|
26
|
+
cy.wait('@getUsers').then(({ response }) => {
|
|
27
|
+
const users = response.body;
|
|
28
|
+
expect(users).to.have.length(1);
|
|
29
|
+
expect(users[0].grantedAuthorities).to.have.length(1);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
UserAndAccessSteps.getTableRow().should('have.length', 1);
|
|
33
|
+
UserAndAccessSteps.findUserInTable('admin')
|
|
34
|
+
.within(() => {
|
|
35
|
+
cy.get('.username').should('contain', 'admin');
|
|
36
|
+
});
|
|
37
|
+
UserAndAccessSteps.getToggleSecurityCheckbox().should('not.be.checked');
|
|
38
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"enabled": false,
|
|
3
|
+
"authorities": [
|
|
4
|
+
"READ_REPO_configurations@http://localhost:7202"
|
|
5
|
+
],
|
|
6
|
+
"appSettings": {
|
|
7
|
+
"DEFAULT_INFERENCE": true,
|
|
8
|
+
"DEFAULT_VIS_GRAPH_SCHEMA": true,
|
|
9
|
+
"DEFAULT_SAMEAS": true,
|
|
10
|
+
"IGNORE_SHARED_QUERIES": false,
|
|
11
|
+
"EXECUTE_COUNT": true
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "id",
|
|
3
|
+
"name": "Quadro",
|
|
4
|
+
"model": "gpt-4o",
|
|
5
|
+
"api": "openai-assistants",
|
|
6
|
+
"contextSize": 128000,
|
|
7
|
+
"temperature": 0.7,
|
|
8
|
+
"topP": 1.0,
|
|
9
|
+
"seed": 0,
|
|
10
|
+
"repositoryId": "test-repository",
|
|
11
|
+
"instructions": {
|
|
12
|
+
"systemInstruction": "",
|
|
13
|
+
"userInstruction": "If you need to write a SPARQL query, use only the classes and properties provided in the schema and don't invent or guess any. Always try to return human-readable names or labels and not only the IRIs. If SPARQL fails to provide the necessary information you can try another tool too."
|
|
14
|
+
},
|
|
15
|
+
"assistantExtractionMethods": [
|
|
16
|
+
{
|
|
17
|
+
"method": "sparql_search",
|
|
18
|
+
"ontologyGraph": "http://example.com",
|
|
19
|
+
"sparqlQuery": "CONSTRUCT {?s ?p ?o} WHERE {GRAPH <http://example.org/ontology> {?s ?p ?o .}}",
|
|
20
|
+
"addMissingNamespaces": false
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"method": "fts_search",
|
|
24
|
+
"maxNumberOfTriplesPerCall": 0
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"method": "similarity_search",
|
|
28
|
+
"similarityIndex": "similarity-index",
|
|
29
|
+
"similarityIndexThreshold": 0.6,
|
|
30
|
+
"maxNumberOfTriplesPerCall": 0
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"method": "retrieval_search",
|
|
34
|
+
"retrievalConnectorInstance": "retrieval-connector",
|
|
35
|
+
"queryTemplate": "{\"query\": \"string\"}",
|
|
36
|
+
"maxNumberOfTriplesPerCall": 0
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"additionalExtractionMethods": [
|
|
40
|
+
{
|
|
41
|
+
"method": "iri_discovery_search"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|