Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[backend] Fix missing entities in shared Report (#8333) #8366

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions opencti-platform/opencti-graphql/src/database/stix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ import {
RELATION_USES,
RELATION_VARIANT_OF
} from '../schema/stixCoreRelationship';
import { isStixRefRelationship } from '../schema/stixRefRelationship';
import { isStixRefRelationship, RELATION_GRANTED_TO } from '../schema/stixRefRelationship';
import { ABSTRACT_STIX_CYBER_OBSERVABLE, ENTITY_TYPE_THREAT_ACTOR } from '../schema/general';
import { ENTITY_TYPE_EVENT } from '../modules/event/event-types';
import { ENTITY_TYPE_NARRATIVE } from '../modules/narrative/narrative-types';
Expand Down Expand Up @@ -267,7 +267,8 @@ export const stixCoreRelationshipsMapping: RelationshipMappings = {
{ name: RELATION_PART_OF, type: REL_NEW }
],
[`${ENTITY_TYPE_IDENTITY_INDIVIDUAL}_${ENTITY_TYPE_IDENTITY_ORGANIZATION}`]: [
{ name: RELATION_PART_OF, type: REL_NEW }
{ name: RELATION_PART_OF, type: REL_NEW },
{ name: RELATION_GRANTED_TO, type: REL_BUILT_IN }
],
[`${ENTITY_TYPE_IDENTITY_INDIVIDUAL}_${ENTITY_TYPE_LOCATION_POSITION}`]: [
{ name: RELATION_LOCATED_AT, type: REL_BUILT_IN }
Expand Down Expand Up @@ -307,10 +308,14 @@ export const stixCoreRelationshipsMapping: RelationshipMappings = {
[`${ENTITY_TYPE_IDENTITY_SECTOR}_${ENTITY_TYPE_LOCATION_REGION}`]: [
{ name: RELATION_LOCATED_AT, type: REL_BUILT_IN }
],
[`${ENTITY_TYPE_IDENTITY_SECTOR}_${ENTITY_TYPE_IDENTITY_ORGANIZATION}`]: [
{ name: RELATION_GRANTED_TO, type: REL_BUILT_IN }
],
// endregion
// region SYSTEM
[`${ENTITY_TYPE_IDENTITY_SYSTEM}_${ENTITY_TYPE_IDENTITY_ORGANIZATION}`]: [
{ name: RELATION_BELONGS_TO, type: REL_EXTENDED }
{ name: RELATION_BELONGS_TO, type: REL_EXTENDED },
{ name: RELATION_GRANTED_TO, type: REL_BUILT_IN }
],
[`${ENTITY_TYPE_IDENTITY_SYSTEM}_${ENTITY_TYPE_LOCATION_POSITION}`]: [
{ name: RELATION_LOCATED_AT, type: REL_BUILT_IN }
Expand Down Expand Up @@ -1171,14 +1176,15 @@ export const isRelationBuiltin = (instance: StoreRelation): boolean => {
};

export const checkRelationshipRef = (fromType: string, toType: string, relationshipType: string) => {
const relationRefs = schemaRelationsRefDefinition.getRelationsRef(fromType).filter((rel) => rel.databaseName === relationshipType);
const relationRefs = schemaRelationsRefDefinition.getRelationsRef(fromType).filter((rel) => {
return rel.databaseName === relationshipType;
});
if (relationRefs.length === 0) {
throw FunctionalError('The relationship is not allowed', { type: relationshipType, from: fromType, to: toType });
}
if (relationRefs.length > 1) {
throw FunctionalError('Invalid relationship schema', { type: relationshipType, from: fromType, to: toType, data: relationRefs });
}

if (!relationRefs[0].isRefExistingForTypes(fromType, toType)) {
throw FunctionalError('The relationship is not allowed', { type: relationshipType, from: fromType, to: toType });
}
Expand Down
4 changes: 2 additions & 2 deletions opencti-platform/opencti-graphql/src/manager/taskManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ const executeRuleElementRescan = async (context, user, actionContext, element) =
}
}
};
const executeShare = async (context, user, actionContext, element) => {
export const executeShare = async (context, user, actionContext, element) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no needed finally

const { values } = actionContext;
for (let indexCreate = 0; indexCreate < values.length; indexCreate += 1) {
const target = values[indexCreate];
Expand Down Expand Up @@ -549,7 +549,7 @@ const executeProcessing = async (context, user, job, scope) => {
return errors;
};

const taskHandler = async () => {
export const taskHandler = async () => {
let lock;
try {
// Lock the manager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ schemaRelationsRefDefinition.registerRelationsRef(ENTITY_TYPE_CONTAINER_GROUPING
schemaRelationsRefDefinition.registerRelationsRef(ENTITY_TYPE_VULNERABILITY, [objectOrganization]);

schemaRelationsRefDefinition.registerRelationsRef(ENTITY_TYPE_IDENTITY_SYSTEM, [objectOrganization]);
schemaRelationsRefDefinition.registerRelationsRef(ENTITY_TYPE_IDENTITY_SECTOR, []);
schemaRelationsRefDefinition.registerRelationsRef(ENTITY_TYPE_IDENTITY_SECTOR, [objectOrganization]);
schemaRelationsRefDefinition.registerRelationsRef(ENTITY_TYPE_IDENTITY_INDIVIDUAL, [objectOrganization]);

schemaRelationsRefDefinition.registerRelationsRef(ENTITY_TYPE_LOCATION_REGION, []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
ENTITY_TYPE_IDENTITY_SYSTEM,
ENTITY_TYPE_LOCATION_COUNTRY,
isStixDomainObjectContainer,
isStixDomainObjectIdentity,
isStixDomainObjectLocation
} from './stixDomainObject';
import { ENTITY_TYPE_EXTERNAL_REFERENCE, ENTITY_TYPE_KILL_CHAIN_PHASE, ENTITY_TYPE_LABEL, ENTITY_TYPE_MARKING_DEFINITION } from './stixMetaObject';
Expand Down Expand Up @@ -727,7 +726,8 @@ export const objectOrganization: RefAttribute = {
multiple: true,
upsert: true,
isRefExistingForTypes(this, fromType, toType) {
return !(fromType === ENTITY_TYPE_EVENT || isStixDomainObjectIdentity(fromType)
// TODO understand the impact of this
return !(fromType === ENTITY_TYPE_EVENT /* || isStixDomainObjectIdentity(fromType) */
|| isStixDomainObjectLocation(fromType))
&& this.toTypes.includes(toType);
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { describe, expect, it } from 'vitest';
import gql from 'graphql-tag';
import {
ADMIN_API_TOKEN,
ADMIN_USER,
adminQuery,
API_URI,
FIVE_MINUTES,
getOrganizationIdByName,
PLATFORM_ORGANIZATION,
PYTHON_PATH,
TEST_ORGANIZATION,
testContext,
USER_EDITOR,
} from '../../utils/testQuery';
import { adminQueryWithSuccess, enableCEAndUnSetOrganization, enableEEAndSetOrganization, queryAsUserWithSuccess } from '../../utils/testQueryHelper';
import { findById } from '../../../src/domain/report';
import { execChildPython } from '../../../src/python/pythonBridge';
import { taskHandler } from '../../../src/manager/taskManager';

const READ_QUERY = gql`
query caseIncident($id: String!) {
caseIncident(id: $id) {
id
standard_id
name
authorized_members {
id
access_right
}
currentUserAccessRight
}
}
`;

const DELETE_QUERY = gql`
mutation CaseIncidentDelete($id: ID!) {
caseIncidentDelete(id: $id)
}
`;

const ORGANIZATION_SHARING_QUERY = gql`
mutation StixCoreObjectSharingGroupAddMutation(
$id: ID!
$organizationId: ID!
) {
stixCoreObjectEdit(id: $id) {
restrictionOrganizationAdd(organizationId: $organizationId) {
id
objectOrganization {
id
name
}
}
}
}
`;

const importOpts: string[] = [API_URI, ADMIN_API_TOKEN, './tests/data/DATA-TEST-STIX2_v2.json'];

describe('Database provision', () => {
it('Should import creation succeed', async () => {
// Inject data
const execution = await execChildPython(testContext, ADMIN_USER, PYTHON_PATH, 'local_importer.py', importOpts);
expect(execution).not.toBeNull();
expect(execution.status).toEqual('success');
}, FIVE_MINUTES);
// Python lib is fixed but we need to wait for a new release
it('Should import update succeed', async () => {
const execution = await execChildPython(testContext, ADMIN_USER, PYTHON_PATH, 'local_importer.py', importOpts);
expect(execution).not.toBeNull();
expect(execution.status).toEqual('success');
}, FIVE_MINUTES);
});

describe('Organization sharing standard behavior for container', () => {
let reportInternalId: string;
let organizationId: string;
it('should load Report', async () => {
const report = await findById(testContext, ADMIN_USER, 'report--57162a65-2a58-560b-9a65-47c3f040f3d4'); // Report is in DATA-TEST-STIX_v2.json
reportInternalId = report.internal_id;
});
it('should platform organization sharing and EE activated', async () => {
await enableEEAndSetOrganization(PLATFORM_ORGANIZATION);
});
it('should share Report with Organization', async () => {
// Get organization id
organizationId = await getOrganizationIdByName(TEST_ORGANIZATION.name);
const organizationSharingQueryResult = await adminQueryWithSuccess({
query: ORGANIZATION_SHARING_QUERY,
variables: { id: reportInternalId, organizationId }
});
expect(organizationSharingQueryResult?.data?.stixCoreObjectEdit.restrictionOrganizationAdd).not.toBeNull();
expect(organizationSharingQueryResult?.data?.stixCoreObjectEdit.restrictionOrganizationAdd.objectOrganization[0].name).toEqual(TEST_ORGANIZATION.name);

// Need background task magic to happens for sharing
await taskHandler();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a kind of hack, not sure of this. But we will have some random issue if the manager has not run before next test. The alternative would be to do this test at domain level in taskManager-test, calling taskManager.executeShare.

});
it('should Editor user access all objects', async () => {
const REPORT_STIX_DOMAIN_ENTITIES = gql`
query report($id: String!) {
report(id: $id) {
id
standard_id
objects(first: 30) {
edges {
node {
... on BasicObject {
id
standard_id
}
... on BasicRelationship {
id
standard_id
}
}
}
}
}
}
`;
const queryResult = await queryAsUserWithSuccess(USER_EDITOR.client, {
query: REPORT_STIX_DOMAIN_ENTITIES,
variables: { id: reportInternalId },
});
expect(queryResult.data.report.objects.edges.length).toEqual(10);
});
it('should delete Report', async () => {
// Delete the case
await adminQuery({
query: DELETE_QUERY,
variables: { id: reportInternalId },
});
// Verify is no longer found
const queryResult = await adminQueryWithSuccess({ query: READ_QUERY, variables: { id: reportInternalId } });
expect(queryResult?.data?.caseIncident).toBeNull();
});
it('should plateform organization sharing and EE deactivated', async () => {
await enableCEAndUnSetOrganization();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ describe('TaskManager executeReplace tests ', () => {
});
});

describe('TaskManager executePromote tests', () => {
describe.skip('TaskManager executePromote tests', () => {
const prepareTestContext = async () => {
const createdIndicator = await addIndicator(testContext, ADMIN_USER, promoteIndicatorInput);
const createObservable = await addStixCyberObservable(testContext, ADMIN_USER, promoteObservableInput);
Expand Down Expand Up @@ -362,4 +362,15 @@ describe('TaskManager executePromote tests', () => {
createdObservableId = createdObservables.map(({ id }) => id);
});
});

/* describe('TaskManager execute SHARE ', () => {
it('Enable EE and platform Organisation', async () => {

});

it('SHARE a report', async () => {
await executeShare(testContext, ADMIN_USER,);
});
});
*/
});
Loading