// Copyright 2017 clair authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";
option go_package = "clairpb";

package clairpb;
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";

message Vulnerability {
	string name = 1;
	string namespace_name = 2;
	string description = 3;
	string link = 4;
	string severity = 5;
	string metadata = 6;
	// fixed_by exists when vulnerability is under feature.
	string fixed_by = 7;
	// affected_versions exists when vulnerability is under notification.
	repeated Feature affected_versions = 8;
}

message ClairStatus {
	// listers and detectors are processors implemented in this Clair and used to
	// scan ancestries
	repeated string listers = 1;
	repeated string detectors = 2;
	google.protobuf.Timestamp last_update_time = 3;
}

message Feature{
	string name = 1;
	string namespace_name = 2;
	string version = 3;
	string version_format = 4;
	repeated Vulnerability vulnerabilities = 5;
}

message Ancestry {
	string name = 1;
	repeated Feature features = 2;
	repeated Layer layers = 3;

	// scanned_listers and scanned_detectors are used to scan this ancestry, it
	// may be different from listers and detectors in ClairStatus since the
	// ancestry could be scanned by previous version of Clair.
	repeated string scanned_listers = 4;
	repeated string scanned_detectors = 5;
}

message Layer {
	string hash = 1;
}

message Notification {
	string name = 1;
	string created = 2;
	string notified = 3;
	string deleted = 4;	
	PagedVulnerableAncestries old = 5;
	PagedVulnerableAncestries new = 6;
}

message IndexedAncestryName {
	// index is unique to name in all streams simultaneously streamed, increasing
	// and larger than all indexes in previous page in same stream.
	int32 index = 1;
	string name = 2;
}

message PagedVulnerableAncestries {
	string current_page = 1;
	// if next_page is empty, it signals the end of all pages.
	string next_page = 2;
	int32 limit = 3;	
	Vulnerability vulnerability = 4;
	repeated IndexedAncestryName ancestries = 5;
}

message PostAncestryRequest {
	message PostLayer {
		string hash = 1;
		string path = 2;
		map<string, string> headers = 3;
	}
	string ancestry_name = 1;
	string format = 2;
	repeated PostLayer layers = 3;
}

message PostAncestryResponse {
	ClairStatus status = 1; 
}

message GetAncestryRequest {
	string ancestry_name = 1;
	bool with_vulnerabilities = 2;
	bool with_features = 3;
}

message GetAncestryResponse {
	Ancestry ancestry = 1;
	ClairStatus status = 2; 
}

message GetNotificationRequest {
	// if the vulnerability_page is empty, it implies the first page.
	string old_vulnerability_page = 1;
	string new_vulnerability_page = 2;
	int32 limit = 3;
	string name = 4;
}

message GetNotificationResponse {
	Notification notification = 1;
}

message MarkNotificationAsReadRequest {
	string name = 1;
}

service AncestryService{
	rpc PostAncestry(PostAncestryRequest) returns (PostAncestryResponse) {
		option (google.api.http) = {
			post: "/ancestry"
			body: "*"
		};
	}

	rpc GetAncestry(GetAncestryRequest) returns (GetAncestryResponse) {
		option (google.api.http) = {
			get: "/ancestry/{ancestry_name}"
		};
	}
}

service NotificationService{
	rpc GetNotification(GetNotificationRequest) returns (GetNotificationResponse) {
		option (google.api.http) = {
			get: "/notifications/{name}"
		};
	}

	rpc MarkNotificationAsRead(MarkNotificationAsReadRequest) returns (google.protobuf.Empty) {
		option (google.api.http) = {
			delete: "/notifications/{name}"
		};
	}
}