diff --git a/src/api-engine/api/lib/configtxgen/configtx.py b/src/api-engine/api/lib/configtxgen/configtx.py index 83fd98851..2e1345e27 100644 --- a/src/api-engine/api/lib/configtxgen/configtx.py +++ b/src/api-engine/api/lib/configtxgen/configtx.py @@ -52,13 +52,16 @@ def create(self, name, consensus, orderers, peers, orderer_cfg=None, application for orderer in orderers: OrdererMSP = "OrdererMSP" - OrdererOrg = dict(Name="Orderer", - ID= OrdererMSP, - MSPDir='{}/{}/crypto-config/ordererOrganizations/{}/msp'.format(self.filepath, orderer["name"], orderer['name'].split(".", 1)[1]), - Policies=dict(Readers=dict(Type="Signature", Rule="OR('{}.member')".format(OrdererMSP)), - Writers=dict(Type="Signature", Rule="OR('{}.member')".format(OrdererMSP)), - Admins=dict(Type="Signature", Rule="OR('{}.admin')".format(OrdererMSP))) - ) + OrdererOrg = dict( + Name="Orderer", + ID=OrdererMSP, + MSPDir='{}/{}/crypto-config/ordererOrganizations/{}/msp'.format(self.filepath, orderer["name"], orderer['name'].split(".", 1)[1]), + Policies=dict( + Readers=dict(Type="Signature", Rule="OR('{}.member')".format(OrdererMSP)), + Writers=dict(Type="Signature", Rule="OR('{}.member')".format(OrdererMSP)), + Admins=dict(Type="Signature", Rule="OR('{}.admin')".format(OrdererMSP)) + ) + ) for host in orderer['hosts']: OrdererAddress.append('{}.{}:{}'.format(host['name'], orderer['name'].split(".", 1)[1], 7050)) Consenters.append(dict( diff --git a/src/api-engine/api/lib/configtxgen/configtxgen.py b/src/api-engine/api/lib/configtxgen/configtxgen.py index c46c4257c..c3341166d 100644 --- a/src/api-engine/api/lib/configtxgen/configtxgen.py +++ b/src/api-engine/api/lib/configtxgen/configtxgen.py @@ -48,7 +48,7 @@ def genesis(self, profile="", channelid="", outputblock="genesis.block"): except subprocess.CalledProcessError as e: err_msg = "configtxgen genesis fail! " - raise Exception(err_msg+str(e)) + raise Exception(err_msg + str(e)) except Exception as e: err_msg = "configtxgen genesis fail! " @@ -62,4 +62,4 @@ def anchorpeer(self, profile, channelid, outputblock): outputblock: outputblock return: """ - pass \ No newline at end of file + pass diff --git a/src/api-engine/api/lib/configtxlator/configtxlator.py b/src/api-engine/api/lib/configtxlator/configtxlator.py index d25fb42c5..9f5e1aa3a 100644 --- a/src/api-engine/api/lib/configtxlator/configtxlator.py +++ b/src/api-engine/api/lib/configtxlator/configtxlator.py @@ -7,6 +7,7 @@ import logging LOG = logging.getLogger(__name__) + class ConfigTxLator: """ Class represents configtxlator CLI. @@ -32,7 +33,7 @@ def proto_encode(self, input, type, output): "--type={}".format(type), "--output={}".format(output), ] - + LOG.info(" ".join(command)) call(command) @@ -57,7 +58,7 @@ def proto_decode(self, input, type, output): "--input={}".format(input), "--output={}".format(output), ] - + LOG.info(" ".join(command)) call(command) @@ -85,7 +86,7 @@ def compute_update(self, original, updated, channel_id, output): "--channel_id={}".format(channel_id), "--output={}".format(output), ] - + LOG.info(" ".join(command)) call(command) diff --git a/src/api-engine/api/lib/peer/chaincode.py b/src/api-engine/api/lib/peer/chaincode.py index 10e489ebc..c03f6a16a 100644 --- a/src/api-engine/api/lib/peer/chaincode.py +++ b/src/api-engine/api/lib/peer/chaincode.py @@ -10,6 +10,7 @@ LOG = logging.getLogger(__name__) + class ChainCode(Command): def __init__(self, version=FABRIC_VERSION, peer=FABRIC_TOOL, **kwargs): self.peer = peer + "/peer" @@ -70,8 +71,12 @@ def lifecycle_query_installed(self, timeout): "--connTimeout", timeout ] LOG.info(" ".join(command)) - res = subprocess.Popen(command, shell=False, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) + res = subprocess.Popen( + command, + shell=False, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) stdout, stderr = res.communicate() return_code = res.returncode @@ -164,7 +169,7 @@ def lifecycle_approve_for_my_org(self, orderer_url, channel_name, cc_name, "--tls", "--cafile", ORDERER_CA ] - + if init_flag: command.append("--init-required") if policy: @@ -247,7 +252,7 @@ def lifecycle_check_commit_readiness(self, channel_name, cc_name, cc_version, se "--cafile", ORDERER_CA, "--output", "json", ] - + LOG.info(" ".join(command)) res = subprocess.Popen(command, shell=False, @@ -312,13 +317,13 @@ def lifecycle_commit(self, orderer_url, channel_name, cc_name, chaincode_version command.append(peer_list[i]) command.append("--tlsRootCertFiles") command.append(peer_root_certs[i]) - + if init_flag: command.append("--init-required") if policy: command.append("--signature-policy") command.append(policy) - + LOG.info(" ".join(command)) res = os.system(" ".join(command)) res = res >> 8 @@ -442,9 +447,12 @@ def lifecycle_calculatepackageid(self, cc_path): :return: calculated packageid """ try: - res = subprocess.Popen("{} lifecycle chaincode calculatepackageid {} " - .format(self.peer, cc_path), - shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + res = subprocess.Popen( + "{} lifecycle chaincode calculatepackageid {} ".format(self.peer, cc_path), + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) stdout, stderr = res.communicate() return_code = res.returncode if return_code == 0: @@ -455,4 +463,4 @@ def lifecycle_calculatepackageid(self, cc_path): return return_code, stderr except Exception as e: err_msg = "calculated chaincode packageid failed for {}!".format(e) - raise Exception(err_msg) \ No newline at end of file + raise Exception(err_msg) diff --git a/src/api-engine/api/lib/peer/channel.py b/src/api-engine/api/lib/peer/channel.py index 6bf9a257f..abba3d83e 100644 --- a/src/api-engine/api/lib/peer/channel.py +++ b/src/api-engine/api/lib/peer/channel.py @@ -11,6 +11,7 @@ LOG = logging.getLogger(__name__) + class Channel(Command): """Call CMD to perform channel create, join and other related operations""" @@ -47,13 +48,13 @@ def create(self, channel, orderer_admin_url, block_path, time_out="90s"): ] LOG.info(" ".join(command)) - + res = subprocess.run(command, check=True) except subprocess.CalledProcessError as e: err_msg = "create channel failed for {}!".format(e) - raise Exception(err_msg+str(e)) - + raise Exception(err_msg + str(e)) + except Exception as e: err_msg = "create channel failed for {}!".format(e) raise Exception(err_msg) @@ -142,7 +143,7 @@ def fetch(self, block_path, channel, orderer_general_url, max_retries=5, retry_i LOG.info(" ".join(command)) # Retry fetching the block up to max_retries times - for attempt in range(1, max_retries+1): + for attempt in range(1, max_retries + 1): try: LOG.debug("Attempt %d/%d to fetch block", attempt, max_retries) diff --git a/src/api-engine/api/routes/chaincode/serializers.py b/src/api-engine/api/routes/chaincode/serializers.py index e6f0eebad..63f67c5b4 100644 --- a/src/api-engine/api/routes/chaincode/serializers.py +++ b/src/api-engine/api/routes/chaincode/serializers.py @@ -30,8 +30,9 @@ def validate(self, attrs): @staticmethod def extension_for_file(file): - extension = file.name.endswith('.tar.gz') - return extension + extension = file.name.endswith('.tar.gz') + return extension + class ChainCodeNetworkSerializer(serializers.Serializer): id = serializers.UUIDField(help_text="Network ID") diff --git a/src/api-engine/api/routes/chaincode/views.py b/src/api-engine/api/routes/chaincode/views.py index f8247850f..d03038918 100644 --- a/src/api-engine/api/routes/chaincode/views.py +++ b/src/api-engine/api/routes/chaincode/views.py @@ -483,6 +483,83 @@ def check_commit_readiness(self, request): ok(content), status=status.HTTP_200_OK ) + def _get_orderer_url(self, org): + qs = Node.objects.filter(type="orderer", organization=org) + if not qs.exists(): + raise ResourceNotFound("Orderer Does Not Exist") + return qs.first().name + "." + org.name.split(".", 1)[1] + ":" + str(7050) + + def _get_peer_channel_cli(self, org): + qs = Node.objects.filter(type="peer", organization=org) + if not qs.exists(): + raise ResourceNotFound("Peer Does Not Exist") + envs = init_env_vars(qs.first(), org) + return PeerChainCode(**envs) + + def _get_approved_organizations_by_channel_and_chaincode(self, peer_channel_cli, channel_name, chaincode_name, chaincode_version, sequence): + code, readiness_result = peer_channel_cli.lifecycle_check_commit_readiness( + channel_name, chaincode_name, chaincode_version, sequence) + if code != 0: + raise Exception(f"Check commit readiness failed: {readiness_result}") + + # Check approved status + approvals = readiness_result.get("approvals", {}) + approved_msps = [org_msp for org_msp, approved in approvals.items() if approved] + if not approved_msps: + raise Exception("No organizations have approved this chaincode") + + LOG.info(f"Approved organizations: {approved_msps}") + + try: + channel = Channel.objects.get(name=channel_name) + channel_orgs = channel.organizations.all() + except Channel.DoesNotExist: + raise Exception(f"Channel {channel_name} not found") + + # find the corresponding organization by MSP ID + # MSP ID format: Org1MSP, Org2MSP -> organization name format: org1.xxx, org2.xxx + approved_orgs = [] + for msp_id in approved_msps: + if msp_id.endswith("MSP"): + org_prefix = msp_id[:-3].lower() # remove "MSP" and convert to lowercase + # find the corresponding organization in the channel + for channel_org in channel_orgs: + if channel_org.name.split(".")[0] == org_prefix: + approved_orgs.append(channel_org) + LOG.info(f"Found approved organization: {channel_org.name} (MSP: {msp_id})") + break + + if not approved_orgs: + raise Exception("No approved organizations found in this channel") + return approved_orgs + + def _get_peer_addresses_and_certs_by_organizations(self, orgs): + addresses = [] + certs = [] + for org in orgs: + qs = Node.objects.filter(type="peer", organization=org) + if not qs.exists(): + LOG.warning(f"No peer nodes found for organization: {org.name}") + continue + + # select the first peer node for each organization + peer = qs.first() + peer_tls_cert = "{}/{}/crypto-config/peerOrganizations/{}/peers/{}/tls/ca.crt".format( + CELLO_HOME, + org.name, + org.name, + peer.name + "." + org.name + ) + peer_address = peer.name + "." + org.name + ":" + str(7051) + LOG.info(f"Added peer from org {org.name}: {peer_address}") + + addresses.append(peer_address) + certs.append(peer_tls_cert) + + if not addresses: + raise Exception("No peer nodes found for specified organizations") + return addresses, certs + @swagger_auto_schema( method="post", responses=with_common_response( @@ -500,92 +577,32 @@ def commit(self, request): policy = serializer.validated_data.get("policy") sequence = serializer.validated_data.get("sequence") init_flag = serializer.validated_data.get("init_flag", False) - org = request.user.organization - qs = Node.objects.filter(type="orderer", organization=org) - if not qs.exists(): - raise ResourceNotFound("Orderer Does Not Exist") - orderer_node = qs.first() - orderer_url = orderer_node.name + "." + org.name.split(".", 1)[1] + ":" + str(7050) + + orderer_url = self._get_orderer_url(org) # Step 1: Check commit readiness, find all approved organizations - qs = Node.objects.filter(type="peer", organization=org) - if not qs.exists(): - raise ResourceNotFound("Peer Does Not Exist") - peer_node = qs.first() - envs = init_env_vars(peer_node, org) - - peer_channel_cli = PeerChainCode(**envs) - code, readiness_result = peer_channel_cli.lifecycle_check_commit_readiness( - channel_name, chaincode_name, chaincode_version, sequence) - if code != 0: - return Response(err(f"Check commit readiness failed: {readiness_result}"), - status=status.HTTP_400_BAD_REQUEST) - - # Check approved status - approvals = readiness_result.get("approvals", {}) - approved_orgs = [org_msp for org_msp, approved in approvals.items() if approved] - if not approved_orgs: - return Response(err("No organizations have approved this chaincode"), - status=status.HTTP_400_BAD_REQUEST) - - LOG.info(f"Approved organizations: {approved_orgs}") - - # Step 2: Get channel organizations and peer nodes - try: - channel = Channel.objects.get(name=channel_name) - channel_orgs = channel.organizations.all() - except Channel.DoesNotExist: - return Response(err(f"Channel {channel_name} not found"), - status=status.HTTP_400_BAD_REQUEST) - - # find the corresponding organization by MSP ID - # MSP ID format: Org1MSP, Org2MSP -> organization name format: org1.xxx, org2.xxx - approved_organizations = [] - for msp_id in approved_orgs: - if msp_id.endswith("MSP"): - org_prefix = msp_id[:-3].lower() # remove "MSP" and convert to lowercase - # find the corresponding organization in the channel - for channel_org in channel_orgs: - if channel_org.name.split(".")[0] == org_prefix: - approved_organizations.append(channel_org) - LOG.info(f"Found approved organization: {channel_org.name} (MSP: {msp_id})") - break - - if not approved_organizations: - return Response(err("No approved organizations found in this channel"), - status=status.HTTP_400_BAD_REQUEST) - - # get peer nodes and root certs - peer_address_list = [] - peer_root_certs = [] - - for approved_org in approved_organizations: - org_peer_nodes = Node.objects.filter(type="peer", organization=approved_org) - if org_peer_nodes.exists(): - # select the first peer node for each organization - peer = org_peer_nodes.first() - peer_tls_cert = "{}/{}/crypto-config/peerOrganizations/{}/peers/{}/tls/ca.crt" \ - .format(CELLO_HOME, approved_org.name, approved_org.name, - peer.name + "." + approved_org.name) - peer_address = peer.name + "." + approved_org.name + ":" + str(7051) - peer_address_list.append(peer_address) - peer_root_certs.append(peer_tls_cert) - LOG.info(f"Added peer from approved org {approved_org.name}: {peer_address}") - else: - LOG.warning(f"No peer nodes found for approved organization: {approved_org.name}") + peer_channel_cli = self._get_peer_channel_cli(org) + approved_organizations = self._get_approved_organizations_by_channel_and_chaincode( + peer_channel_cli, + channel_name, + chaincode_name, + chaincode_version, + sequence + ) - if not peer_address_list: - return Response(err("No peer nodes found for approved organizations"), - status=status.HTTP_400_BAD_REQUEST) + # Step 2: Get peer nodes and root certs + peer_address_list, peer_root_certs = self._get_peer_addresses_and_certs_by_organizations(approved_organizations) # Step 3: Commit chaincode code = peer_channel_cli.lifecycle_commit( - orderer_url, channel_name, chaincode_name, chaincode_version, + orderer_url, channel_name, chaincode_name, chaincode_version, sequence, policy, peer_address_list, peer_root_certs, init_flag) if code != 0: - return Response(err("Commit chaincode failed"), - status=status.HTTP_400_BAD_REQUEST) + return Response( + err("Commit chaincode failed"), + status=status.HTTP_400_BAD_REQUEST + ) LOG.info(f"Chaincode {chaincode_name} committed successfully") @@ -601,7 +618,7 @@ def commit(self, request): except Exception as e: LOG.error(f"Commit chaincode failed: {str(e)}") return Response( - err(f"Commit chaincode failed: {str(e)}"), + err(f"Commit chaincode failed: {str(e)}"), status=status.HTTP_400_BAD_REQUEST ) diff --git a/src/api-engine/api/routes/channel/views.py b/src/api-engine/api/routes/channel/views.py index ddbd010f3..20af8470b 100644 --- a/src/api-engine/api/routes/channel/views.py +++ b/src/api-engine/api/routes/channel/views.py @@ -62,7 +62,7 @@ class ChannelViewSet(viewsets.ViewSet): permission_classes = [IsAuthenticated, ] parser_classes = [MultiPartParser, FormParser, JSONParser] - @ swagger_auto_schema( + @swagger_auto_schema( query_serializer=PageQuerySerializer, responses=with_common_response( {status.HTTP_201_CREATED: ChannelListResponse} @@ -366,15 +366,17 @@ def get_channel_org_config(self, request, pk=None): LOG.exception("channel org not found") raise ResourceNotFound + def validate_nodes(nodes): - """ - validate if all nodes are running - :param nodes: list of nodes - :return: none - """ - for node in nodes: - if node.status != "running": - raise NoResource("Node {} is not running".format(node.name)) + """ + validate if all nodes are running + :param nodes: list of nodes + :return: none + """ + for node in nodes: + if node.status != "running": + raise NoResource("Node {} is not running".format(node.name)) + def assemble_transaction_config(org): """ @@ -407,11 +409,17 @@ def osn_channel_join(name, ordering_node, org): peer_channel_cli.create( channel=name, orderer_admin_url="{}.{}:{}".format( - ordering_node.name, org.name.split(".", 1)[1], str(7053)), + ordering_node.name, + org.name.split(".", 1)[1], str(7053) + ), block_path="{}/{}/{}.block".format( - CELLO_HOME, org.network.name, name) + CELLO_HOME, + org.network.name, + name + ) ) + def peer_channel_join(name, peers, org): """ Join peer nodes to the channel. @@ -429,6 +437,7 @@ def peer_channel_join(name, peers, org): CELLO_HOME, org.network.name, name) ) + def set_anchor_peer(name, org, anchor_peer, ordering_node): """ Set anchor peer for the channel. @@ -439,7 +448,7 @@ def set_anchor_peer(name, org, anchor_peer, ordering_node): """ org_msp = '{}'.format(org.name.split(".", 1)[0].capitalize()) channel_artifacts_path = "{}/{}".format(CELLO_HOME, org.network.name) - + # Fetch the channel block from the orderer peer_channel_fetch(name, org, anchor_peer, ordering_node) @@ -449,7 +458,7 @@ def set_anchor_peer(name, org, anchor_peer, ordering_node): type="common.Block", output="{}/config_block.json".format(channel_artifacts_path), ) - + # Get the config data from the block json_filter( input="{}/config_block.json".format(channel_artifacts_path), @@ -532,9 +541,15 @@ def peer_channel_fetch(name, org, anchor_peer, ordering_node): """ envs = init_env_vars(anchor_peer, org) peer_channel_cli = PeerChannel(**envs) - peer_channel_cli.fetch(block_path="{}/{}/config_block.pb".format(CELLO_HOME, org.network.name), - channel=name, orderer_general_url="{}.{}:{}".format( - ordering_node.name, org.name.split(".", 1)[1], str(7050))) + peer_channel_cli.fetch( + block_path="{}/{}/config_block.pb".format(CELLO_HOME, org.network.name), + channel=name, orderer_general_url="{}.{}:{}".format( + ordering_node.name, + org.name.split(".", 1)[1], + str(7050) + ) + ) + def peer_channel_update(name, org, anchor_peer, ordering_node, channel_artifacts_path): """ diff --git a/src/api-engine/api/routes/node/views.py b/src/api-engine/api/routes/node/views.py index 0ea65aab2..1cd586f85 100644 --- a/src/api-engine/api/routes/node/views.py +++ b/src/api-engine/api/routes/node/views.py @@ -358,7 +358,8 @@ def _set_port(self, type, node, agent): [{"internal": 7050, "external": ports[0]}, { "internal": 7053, "external": ports[1]}, { "internal": 9443, "external": ports[2]}], - True) + True + ) def _conversion_msp_tls_cfg(self, type, org, node): """ diff --git a/src/api-engine/api/utils/common.py b/src/api-engine/api/utils/common.py index 6d0ddd89e..2d3f434ed 100644 --- a/src/api-engine/api/utils/common.py +++ b/src/api-engine/api/utils/common.py @@ -19,6 +19,7 @@ LOG = logging.getLogger(__name__) + def make_uuid(): return str(uuid.uuid4()) @@ -162,11 +163,11 @@ def to_dict(data): def json_filter(input, output, expression): """ Process JSON data using path expression similar to jq - + Args: input (str): JSON data or file path to JSON output (str): Path expression like ".data.data[0].payload.data.config" - + Returns: dict: Processed JSON data """ @@ -176,11 +177,11 @@ def json_filter(input, output, expression): data = json.load(f) else: data = input - + # parse the path expression path_parts = expression.strip('.').split('.') result = data - + for part in path_parts: # handle array index, like data[0] if '[' in part and ']' in part: @@ -189,12 +190,13 @@ def json_filter(input, output, expression): result = result[array_name][index] else: result = result[part] - + with open(output, 'w', encoding='utf-8') as f: json.dump(result, f, sort_keys=False, indent=4) LOG.info("jq {} {} -> {}".format(expression, input, output)) + def json_add_anchor_peer(input, output, anchor_peer_config, org_msp): """ Add anchor peer to the organization @@ -210,25 +212,26 @@ def json_add_anchor_peer(input, output, anchor_peer_config, org_msp): data = json.load(f) else: data = input - + if "groups" not in data["channel_group"]: data["channel_group"]["groups"] = {} if "Application" not in data["channel_group"]["groups"]: data["channel_group"]["groups"]["Application"] = {"groups": {}} if org_msp not in data["channel_group"]["groups"]["Application"]["groups"]: data["channel_group"]["groups"]["Application"]["groups"][org_msp] = {"values": {}} - + data["channel_group"]["groups"]["Application"]["groups"][org_msp]["values"].update(anchor_peer_config) - + with open(output, 'w', encoding='utf-8') as f: json.dump(data, f, sort_keys=False, indent=4) - + LOG.info("jq '.channel_group.groups.Application.groups.Org1MSP.values += ... ' {} -> {}".format(input, output)) + def json_create_envelope(input, output, channel): """ Create a config update envelope structure - + Args: input (str): Path to the config update JSON file output (str): Path to save the envelope JSON @@ -238,7 +241,7 @@ def json_create_envelope(input, output, channel): # Read the config update file with open(input, 'r', encoding='utf-8') as f: config_update = json.load(f) - + # Create the envelope structure envelope = { "payload": { @@ -253,17 +256,18 @@ def json_create_envelope(input, output, channel): } } } - + # Write the envelope to output file with open(output, 'w', encoding='utf-8') as f: json.dump(envelope, f, sort_keys=False, indent=4) - + LOG.info("echo 'payload ... ' | jq . > {}".format(output)) - + except Exception as e: LOG.error("Failed to create config update envelope: {}".format(str(e))) raise + def init_env_vars(node, org): """ Initialize environment variables for peer channel CLI. @@ -280,14 +284,14 @@ def init_env_vars(node, org): envs = {} - if(node.type == "orderer"): + if (node.type == "orderer"): envs = { "CORE_PEER_TLS_ENABLED": "true", "ORDERER_CA": "{}/orderers/{}/msp/tlscacerts/tlsca.{}-cert.pem".format(dir_certificate, node.name + "." + org_domain, org_domain), "ORDERER_ADMIN_TLS_SIGN_CERT": "{}/orderers/{}/tls/server.crt".format(dir_certificate, node.name + "." + org_domain), "ORDERER_ADMIN_TLS_PRIVATE_KEY": "{}/orderers/{}/tls/server.key".format(dir_certificate, node.name + "." + org_domain) } - elif(node.type == "peer"): + elif (node.type == "peer"): envs = { "CORE_PEER_TLS_ENABLED": "true", "CORE_PEER_LOCALMSPID": "{}MSP".format(org_name.split(".")[0].capitalize()), @@ -298,4 +302,4 @@ def init_env_vars(node, org): "FABRIC_CFG_PATH": "{}/{}/peers/{}/".format(dir_node, org_name, node.name + "." + org_name) } - return envs \ No newline at end of file + return envs diff --git a/src/api-engine/api/validators.py b/src/api-engine/api/validators.py index 3d99a64ff..e87eeb0e5 100644 --- a/src/api-engine/api/validators.py +++ b/src/api-engine/api/validators.py @@ -8,6 +8,7 @@ _url_validator = URLValidator() + def validate_url(value): try: _url_validator(value) diff --git a/src/api-engine/api_engine/settings.py.example b/src/api-engine/api_engine/settings.py.example index 1057218b5..c25f700ac 100644 --- a/src/api-engine/api_engine/settings.py.example +++ b/src/api-engine/api_engine/settings.py.example @@ -171,13 +171,13 @@ SWAGGER_SETTINGS = { "VALIDATOR_URL": None, "DEFAULT_INFO": "api_engine.urls.swagger_info", "SECURITY_DEFINITIONS": { - "JWT": { - "type": "apiKey", - "name": "Authorization", - "in": "header" - } - }, - "USE_SESSION_AUTH": False + "JWT": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + }, + "USE_SESSION_AUTH": False } LOGGING = { diff --git a/src/api-engine/tox.ini b/src/api-engine/tox.ini index 6c203fffb..67872a212 100644 --- a/src/api-engine/tox.ini +++ b/src/api-engine/tox.ini @@ -5,7 +5,7 @@ # [tox] minversion=2.3.1 -envlist = py35, flake8 +envlist = py38, flake8 skipsdist=True skip_missing_interpreters=True @@ -24,4 +24,4 @@ commands = flake8 {toxinidir} [gh-actions] python = - 3.5: py35, flake8 + 3.8: py38, flake8